android listview using simple_list_item_checked onItemLongClick not checking as expected

689 Views Asked by At

I have a ListView using android.R.layout.simple_list_item_checked that I want to set both an onItemLongClick() listener and an onItemClick() listener to do different things. How can I make ONLY the long click to check/uncheck the item, not the (short) click? Thanks

I have tried having the long click return false so it does not consume the event but long clicks will not check/uncheck. Only the short click will. I also tried artificially undoing the checking in the short click (commented out code) but that does not behave as intended.

If I remove the short click callback, the long click still will not check/uncheck. In addition, short clicks will continue to check/uncheck.

EDIT - let me present the code in entirety:

package com.example.checked;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ListView myListView;
    ArrayList<String> myData = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myListView = (ListView) findViewById(R.id.myListView);

        // test data
        myData = new ArrayList<String>();
        myData.add("apple");
        myData.add("banana");
        myData.add("cherry");
        myData.add("durian");
        myData.add("eggplant");

        ArrayAdapter myAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_checked, myData) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                CheckedTextView ctv = (CheckedTextView) view.findViewById(android.R.id.text1);
                ctv.setFocusable(false);
                ctv.setText(myData.get(position));
                ((ListView)parent).setItemChecked(position, false);
                return view;
            }
        };

        myListView.setAdapter(myAdapter);
        myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                CheckedTextView ctv = (CheckedTextView) view;
                Log.i("onItemLongClick", "position=" + position + ", id=" + id + ", isChecked=" + ctv.isChecked());
                // do something
                return false;
            }
        });

        myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                CheckedTextView ctv = (CheckedTextView) view;
                Log.i("onItemClick", "position=" + position + ", id=" + id + ", isChecked=" + ctv.isChecked());
                //if (ctv.isChecked()) ctv.setChecked(false);
                //else if (!ctv.isChecked()) ctv.setChecked(true);
                // do something else
            }
        });
    }
}

And the xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="com.example.checked.MainActivity">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:weightSum="100">

        <ListView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_alignParentTop="true"
            android:layout_weight="80"
            android:id="@+id/myListView" />

    </LinearLayout>

</RelativeLayout>

The log output from doing the following:

  • long click on "apple"
  • long click on "apple" again
  • short click on "banana"
  • short click on "banana" again

01-17 10:23:45.628 14928-14928/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=false 01-17 10:23:46.242 14928-14928/com.example.checked I/onItemClick: position=0, id=0, isChecked=true 01-17 10:23:50.655 14928-14928/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=true 01-17 10:23:51.002 14928-14928/com.example.checked I/onItemClick: position=0, id=0, isChecked=false 01-17 10:23:53.756 14928-14928/com.example.checked I/onItemClick: position=1, id=1, isChecked=true 01-17 10:23:55.131 14928-14928/com.example.checked I/onItemClick: position=1, id=1, isChecked=false

What the above means is that the onItemLongClick() is not checking/unchecking the item and only the onItemLick() is, which is exactly the opposite of what I want.

Edit #2 - I tried changing the listview xml to the following while keeping java code unchanged:

<ListView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_weight="80"
android:longClickable="true"
android:clickable="false"
android:id="@+id/myListView" />

But the short click still takes effect giving the following log:

01-17 10:38:18.703 25598-25598/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=false 01-17 10:38:18.973 25598-25598/com.example.checked I/onItemClick: position=0, id=0, isChecked=true 01-17 10:38:22.212 25598-25598/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=true 01-17 10:38:22.353 25598-25598/com.example.checked I/onItemClick: position=0, id=0, isChecked=false 01-17 10:38:28.951 25598-25598/com.example.checked I/onItemClick: position=1, id=1, isChecked=true 01-17 10:38:30.391 25598-25598/com.example.checked I/onItemClick: position=1, id=1, isChecked=false

EDIT #3 - now if I make onItemLongClick() return true instead of false, long clicks still will not check/uncheck but the short clicks continue to check/uncheck, giving the following log:

01-17 10:43:45.181 28980-28980/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=false 01-17 10:43:49.386 28980-28980/com.example.checked I/onItemLongClick: position=0, id=0, isChecked=false 01-17 10:43:53.662 28980-28980/com.example.checked I/onItemClick: position=1, id=1, isChecked=true 01-17 10:43:55.211 28980-28980/com.example.checked I/onItemClick: position=1, id=1, isChecked=false

2

There are 2 best solutions below

0
On

Add android:longClickable="true" to your listview.

0
On

If you would like to force checking/unchecking items by onItemClick use this:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {

        CheckedTextView v = (CheckedTextView) view;
        boolean currentCheck = v.isChecked();

        if(currentCheck == true){
            ((ListView) adapterView).setItemChecked(position, false);
        }else{
            ((ListView) adapterView).setItemChecked(position, false);
        }
    }
});

If you would like use onItemLongClick() to check/uncheck the item try this:

listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {

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

                CheckedTextView v = (CheckedTextView) view;
                boolean currentCheck = v.isChecked();
                if (currentCheck == true){
                    ((ListView) adapterView).setItemChecked(position, false);
                }else{
                    ((ListView) adapterView).setItemChecked(position, true);
                }


                return true;
            }
        });