Enable/Disable item selection at listview in multiple choice mode

jmhostalet picture jmhostalet · Jan 21, 2013 · Viewed 7.6k times · Source

I have a listview registered for context menu in multiple choice mode:

private void initListViewForContextMenu(){
    log.d("FilesFragment", "initListViewForContextMenu()");
    ListView listView = getListView();
    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { ...

The problem is that not all the items of my view should be selectable, only those showing a special icon should be available for selection. I don't know how to implement this, I've defined an OnItemLongClickListener:

getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> adapter, View view, int position, long id) {
        Log.d("FilesFragment", "OnItemLongClickListener.onItemLongClick at pos " + position);
        PfmDocument doc = (PfmDocument)adapter.getItemAtPosition(position);
        if (doc.isOnBasket()){
            Log.d("FilesFragment", "OnItemLongClickListener.onItemLongClick detected in basket");
            ListView lv = (ListView) adapter;
            lv.setItemChecked(position, false);
        }
        return false;
        }
    }); 

but this listener is never called.

I've also tried to set an OnLongClickListener to the row view in the adapter, but doing this normal click is also disable even when context menu is closed (not in selection mode).

if (doc.isOnBasket()){
    rowView.setOnLongClickListener(new OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        return false; // do nothing, already in basket
    }
});

// }

Answer

Jelle picture Jelle · Jun 18, 2013

If you dig into the android sourcecode (AbsListview), you will see that setting the choiceMode to MULTIPLE_MODAL will take over the longpress. That is why your listener is never called.

You can decide whether a view is clickable by return true/false in isEnabled(position) in your adapter.

The code below only solves the part where during the actionmode, the items that are already added to the basket are not clickable.

But it should be fairly easy to just uncheck the item that is longpressed if it's not a valid item.

Hope this help!

In your MultiChoiceModeListener:

@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu)
{
    this.adapter.setActionMode(true);
    return true;
}

@Override
public void onDestroyActionMode(ActionMode mode)
{
    this.adapter.setActionMode(false);
}

And then in your custom adapter:

public abstract class AbstractCollectionAdapter extends AbstractCursorAdapter
{
    private boolean isActionMode;

    public AbstractCollectionAdapter(Context context)
    {
        super(context);

        this.isActionMode = false;
    }

    @Override
    public boolean isEnabled(int position)
    {
        if (this.isActionMode)
        {
            final Object item = this.getItem(position);
            if (!item.isInBasket())
            {
                //only enable items that are not inside the basket
                return true;
            }
            //all other items are disabled during actionmode
            return false;
        }
        //no actionmode = everything enabled
        return true;
    }

    public void setActionMode(boolean isActionMode)
    {
        this.isActionMode = isActionMode;
    }
}