How to select an ListView item after long click?
Asked Answered
B

2

15

I've got a silly little problem. I've registered a ListFragment both as OnItemClickListener and OnItemLongClickListener of its own ListView.

When the onItemClick event is called, an intent for the detail view activity of that item is started, no problems there.

When the onItemLongClickevent happens, I want to accomplish the following things:

  • Create a CAB
  • Keep the long-pressed item selected

Code:

@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
    if(this.cabMode != null)
        return false;
    this.cabMode = getActivity().startActionMode(editModeCallback);
    view.setSelected(true);
    return true;
}

The CAB will show, however, the selection won't stay with the item.

Some bits and pieces, in case they are relevant: I've read about fixing this issue with calls to view.requestFocusFromTouch() or using listView.setItemChecked(), but that didn't work for me. Also, the views for the list items are instanced from a custom layout, but don't have any custom event listeners attached.

Any help is appreciated. Thx!

Barham answered 29/1, 2013 at 10:19 Comment(4)
pass selected item position after long press.Foehn
Where should I pass it? listView.setItemChecked() takes a position argument, but calling it doesn't have an effect.Barham
Did you do ListView.setChoiceMode(...)? If you don't find a way to fix this, you can always do the selection manually like here goo.gl/7aQAnNavel
No, I did not. Thanks for the pointer. I've tried several combinations of choice modes with calls to either listView.setItemChecked() and view.setSelected(), but still no effect. I'll have a look at the Sherlock code, however I would think, that what I'm trying to do is so basic that there must be an easy way to accomplish it.Barham
B
8

It's possible, but just barely... I actually don't know how such a simple thing can wind up so ridiculously complicated.

The key to the answer can be found here: Android: keep blue background after ListView selection

What this boils down to is to define an additional style that is used by the ListView and setting the choice mode to AbsListView.CHOICE_MODE_SINGLE (as explained in the linked answer).

This allows you programmatically toggle the selection using Listview.setItemChecked(). However, you need to keep track of the index of the touched item in the onItemLongClick callback yourself, because ListView.setSelection() won't do that (at least ListView.getSelectedItem() will always return -1 as far as I can see).

Code (for simplicity, my fragment implements all three OnItemClickListener, OnItemLongClickListener, and ActionMode.Callback):

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    this.listViewAdapter = new ListViewAdapter();
    this.root = (ListView)inflater.inflate(R.layout.fragment_bookmarks, container, false);
    this.root.setAdapter(this.listViewAdapter);
    this.root.setOnItemClickListener(this);
    this.root.setOnItemLongClickListener(this);
    this.root.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
    return this.root;
}

@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
    if(this.cabMode != null)
        return false;
    this.selectedPosition = position;
    this.root.setItemChecked(position, true);

    this.root.setOnItemClickListener(null);
    this.cabMode = getActivity().startActionMode(this);
    return true;
}

And finally, if you want to get rid of the selection when the CAB is closed:

@Override
public void onDestroyActionMode(ActionMode mode) {
    cabMode = null;
    this.root.setItemChecked(this.selectedPosition, false);
    this.selectedPosition = -1;
    this.root.setOnItemClickListener(this);
}

Registering and unregistering the OnItemClickListener makes sure that while the CAB is active you won't accidentally trigger the action usually associated with the item (like opening a detail view).

Barham answered 27/2, 2013 at 12:35 Comment(2)
Chris, note you don't actually need to track the index of the selected item(s). If in choiceMode="singleChoice", use AbsListView.getCheckedItemPosition(). If in choiceMode="multipleChoice", use AbsListView.getCheckedItemPositions() to get the set of checked items. (Note this method is also valid for a single choice mode, but the other method is much simpler.Mucosa
Oh, thanks for the info! I was too fixated on ListView.getSelectedItem() :-)Barham
C
1

My solution:(trick)

final ListView lvMain = (ListView) activity.findViewById(R.id.listTHEMES);
lvMain.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lvMain.setItemsCanFocus(false);

ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity,
            android.R.layout.simple_list_item_multiple_choice, ArrayTheme);
lvMain.setAdapter(adapter);
lvMain.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                                       int pos, long id) {
        // TODO Auto-generated method stub
        if (lvMain.isItemChecked(pos)){lvMain.setItemChecked(pos,false);}else{lvMain.setItemChecked(pos,true);}
        Log.v(LOG_TAG,"long clicked pos: " + pos);
        //lvMain.setSelection();

        return true;
    }
});
lvMain.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {
        //Log.d(LOG_TAG, "itemClick: position = " + position + ", id = " + id);
        if (lvMain.isItemChecked(position)){lvMain.setItemChecked(position,false);}else{lvMain.setItemChecked(position,true);}

    }
});
Clastic answered 31/3, 2017 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.