Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force Listview not to reuse views (Checkbox)

I made a custom Listview (Without overriding getView() method) with each item in a Listview having a following Layout

contactlayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="match_parent" android:weightSum="1">
    <CheckBox android:id="@+id/checkBox1" android:text="CheckBox" android:layout_width="134dp" android:layout_height="108dp" android:focusable="false"></CheckBox>
    <LinearLayout android:id="@+id/linearLayout1" android:layout_height="match_parent" android:orientation="vertical" android:layout_width="87dp" android:layout_weight="0.84" android:weightSum="1" >
        <TextView android:text="TextView" android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/name" android:layout_weight="0.03"></TextView>
        <TextView android:text="TextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/phone"></TextView>
        <TextView android:text="TextView" android:layout_height="wrap_content" android:layout_weight="0.03" android:layout_width="match_parent" android:id="@+id/contactid" android:visibility="invisible"></TextView>
    </LinearLayout>
</LinearLayout>

I am populating the Listview using a SimpleCursorAdapter in a following way...

Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);

        String from[] = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
        int to[] = new int[]{R.id.name,R.id.phone,R.id.contactid};
        SimpleCursorAdapter s = new SimpleCursorAdapter(this,R.layout.contactlayout,c,from,to);
        lv.setAdapter(s);

On Click of a button I am reading the states of all the Checkboxes. The problem is, if I check one CheckBox several others down the line get automatically Checked. I know this is reusing of Views. How do I avoid it ?. I am not even overriding getView() method in this case, so I wonder if there is still any way to achieve what I want?

Answer

Finally I implemented what @sastraxi suggested...

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);

        final CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
        final TextView name = (TextView) view.findViewById(R.id.name);
        final TextView contactId = (TextView) view.findViewById(R.id.contactid);
        final int pos = position;
        checkBox.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                if(checkBox.isChecked())
                {
                    checkList.add(String.valueOf(pos));
                    nameList.add(name.getText().toString());
                    contactList.add(contactId.getText().toString());
                    Log.i("Chk added",String.valueOf(pos));
                }
                else
                {
                    checkList.remove(String.valueOf(pos));
                    nameList.remove(name.getText().toString());
                    contactList.remove(contactId.getText().toString());
                    Log.i("Un Chk removed",String.valueOf(pos));
                }
            }
        });

        if(checkList.contains(String.valueOf(pos)))
        {
            checkBox.setChecked(true);
        }
        else
        {
            checkBox.setChecked(false);
        }

        return view;
    }
like image 588
Shashank Kadne Avatar asked Mar 25 '12 06:03

Shashank Kadne


2 Answers

another way to force not reusing the views, add the following in your cursor adapter:

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    @Override
    public int getViewTypeCount() {
        return 500;
    }

but yes, you should reuse views whenever possible. In my particular case, I am adding images to my views and without forcing to not reuse the view, they would get re-rendered in the reused views.

like image 107
droideckar Avatar answered Oct 01 '22 20:10

droideckar


Ah, I see what the problem is.

Make a new class that extends SimpleCursorAdapter, say CheckboxSimpleCursorAdapter, and override getView as such:

public View getView(int position, View convertView, ViewGroup parent) {
    View view = super.getView(position, convertView, parent);
    CheckBox checkBox = (CheckBox) view.findViewById(R.id.CheckBox1);
    checkBox.setChecked(getIsThisListPositionChecked(position));
    return view;
}

As you're not using a layout whose top-level View implements Checkable, you have to do everything yourself. That includes clearing state (in this case), as the default implementation re-used a View that was checked--as you correctly intuited.

Edit: use this new code, and implement a protected boolean getIsThisListPositionChecked(int position) method that returns whether or not the item is currently checked (or something like that). I hope I'm being clear enough--you need to figure out if the item should be checked according to your model, and then set that when you create the View.

like image 35
sastraxi Avatar answered Oct 01 '22 18:10

sastraxi