ListView OnItemLongClickListener() not triggered
Asked Answered
A

3

6

I have a class that extends ListActivity where the list items respond to OnClick events. Adding an OnItemLongClickListener does not work. The onItemLongClick() function is not called (no log-output or Toast showing) but the normal OnClick() event is handled instead.

I want to display a contextual action bar upon long click. A minimum example using my code in a new project works fine. So my question is: What can possibly prevent the onItemLongClick() trigger from being triggered?

My minimum API is 11. I am also setting the listView to longClickable="true".

Activity code (selected functions):

public class EventListActivity extends ListActivity {

    private ArrayList<Event> arrEvents = null;
    private ArrayAdapter<Event> adpEvents = null;

    private ActionMode mActionMode = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // only create list adapter and set it
        arrEvents = new ArrayList<Event>();
        adpEvents = new ArrayAdapter<Event>(this, android.R.layout.simple_list_item_activated_2, android.R.id.text1, arrEvents) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                TextView text1 = (TextView) view.findViewById(android.R.id.text1);
                TextView text2 = (TextView) view.findViewById(android.R.id.text2);
                text1.setText(arrEvents.get(position).getTitle());
                text2.setText(arrEvents.get(position).getDateTimeFormatted());
                return view;
            }
        };

        setListAdapter(adpEvents);

        // add CAB to ListView
        setupCAB();
    }


    @Override
    protected void onResume() {
        super.onResume();

        // populate list and refresh adapter
        createEventList();
        adpEvents.notifyDataSetChanged();

        // if list empty show emtpy msg, otherwise hide it
        setContentView(R.layout.activity_event_list);
        TextView empty = (TextView) findViewById(R.id.text_empty);
        if(arrEvents.isEmpty()) {
            empty.setVisibility(View.VISIBLE);
        } else {
            empty.setVisibility(View.GONE);
        }
    }


    private void setupCAB() {
        // Important: to select single mode
        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

        getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            // Called when the user long-clicks an item on the list
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View row, int position, long rowid) {
                Log.w("EventListActivity", "Long click detected!");
                Toast.makeText(EventListActivity.this, "Long click detected!", Toast.LENGTH_SHORT).show();
                if (mActionMode != null) {
                    return false;
                }

                // Important: to mark the editing row as activated
                getListView().setItemChecked(position, true);

                // Start the CAB using the ActionMode.Callback defined above
                mActionMode = EventListActivity.this.startActionMode(mActionModeCallback);
                return true;
            }
        });
    }

    private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
        // Called when the action mode is created; startActionMode() was called
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // Inflate a menu resource providing context menu items
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.event_context, menu);
            return true;
        }

        // Called when the user enters the action mode
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // Disable the list to avoid selecting other elements while editing one
            EventListActivity.this.getListView().setEnabled(false);
            return true; // Return false if nothing is done
        }

        // Called when the user selects a contextual menu item
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
            case R.id.mnu_share_event:
                //TODO share event
                mode.finish();
                return true;
            default:
                return false;
            }
        }

        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // Re-enable the list after edition
            EventListActivity.this.getListView().setEnabled(true);
            mActionMode = null;
        }
    };

}

activity_event_list.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".EventListActivity" >

    <TextView
        android:id="@+id/text_empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="45dp"
        android:text="@string/empty"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:visibility="gone" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:longClickable="true" >
    </ListView>

</RelativeLayout>
Assignor answered 29/11, 2013 at 18:46 Comment(0)
D
1

When using a ListActivity or ListFragment there is no method you can override for the long-click, and getting access to the ListView is not possible in onCreateView(), since it is being controlled by the parent class.

So, to overcome this, I did this, since the getListView() command won't work until after the view is created:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecipeListView = this.getListView();
    mRecipeListView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {

        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View view, int position, long row_id) {
            // Process the long-click
        }
    });
}
Declaratory answered 29/11, 2013 at 20:56 Comment(1)
Thanks, the answer is in your last sentence "since the getListView() command won't work until after the view is created" ---> I called my setupCAB() method before calling setContentView(R.layout.activity_event_list); so the list view was not available yet. Where I should have put your code I still don't understand though...Assignor
H
5

If you have buttons responding to onClick() events inside your listview, you need to set the following in the container holding those buttons:

android:descendantFocusability="blocksDescendants"

If what you have are textviews, the problem is slightly trickier. See this: Focusable EditText inside ListView

Handicapped answered 29/11, 2013 at 20:5 Comment(3)
Thanks but I don't have buttons or EditText views inside my ListView. Just normal TextViews (android.R.layout.simple_list_item_activated_2) like I posted in the question.Assignor
Did you try adding the blocksDescendants anyway?Handicapped
Yes but it did not change anything as my problem was of a different origin (see my comment on Rick Falck's answer).Assignor
P
2

This answer does not solve user1's question but the symptoms were similar my problem (i.e. OnItemClickListener was getting called but OnItemLongClickListener was not). I'm posting my answer here in case anyone else stumbles on this question like I did when trying to solve my problem.

I was using a ListView inside a Fragment and implemented the listener methods:

public class MyFragment extends Fragment implements OnClickListener,
        OnLongClickListener, OnItemClickListener, OnItemLongClickListener {

Here is the onItemClick method that was working fine:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long rowId) {

    Log.i("Chimee", "short click working");

}

And here is the onItemLongClick method that wasn't firing:

@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
        long rowId) {

    Log.i("Chimee", "Long click working");
    return false;
}

Of course the simple answer was that I forgot to setOnItemLongClickListener. I added it after the setOnItemClickListener that I had all along and then it worked fine.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.my_fragment, container, false);

    lvSuggestions = (ListView) v.findViewById(R.id.lvSuggestions);
    lvSuggestions.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    lvSuggestions.setOnItemClickListener(this);
    lvSuggestions.setOnItemLongClickListener(this); // Forgot this

    ...
}
Poseidon answered 20/8, 2014 at 2:48 Comment(0)
D
1

When using a ListActivity or ListFragment there is no method you can override for the long-click, and getting access to the ListView is not possible in onCreateView(), since it is being controlled by the parent class.

So, to overcome this, I did this, since the getListView() command won't work until after the view is created:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mRecipeListView = this.getListView();
    mRecipeListView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {

        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View view, int position, long row_id) {
            // Process the long-click
        }
    });
}
Declaratory answered 29/11, 2013 at 20:56 Comment(1)
Thanks, the answer is in your last sentence "since the getListView() command won't work until after the view is created" ---> I called my setupCAB() method before calling setContentView(R.layout.activity_event_list); so the list view was not available yet. Where I should have put your code I still don't understand though...Assignor

© 2022 - 2024 — McMap. All rights reserved.