34

I've seen example com.example.android.apis.view.List11 from ApiDemos. In that example, each row takes the view android.R.simple_list_item_multiple_choice. Each such view has a TextView and a CheckBox.

Now I want each view to have 2 TextViews and 1 CheckBox, somewhat similar to the List3 example. I tried creating a custom layout file row.xml like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <CheckBox
        android:id="@+id/checkbox"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent" />
    <TextView
        android:id="@+id/text_name"
        android:textSize="13px"
        android:textStyle="bold"
        android:layout_toLeftOf="@id/checkbox"
        android:layout_alignParentLeft="true"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/text_phone"
        android:textSize="9px"
        android:layout_toLeftOf="@id/checkbox"
        android:layout_below="@id/text_name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" /> 
</RelativeLayout>

Then in Activity's onCreate(), I do like this:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Query the contacts
    mCursor = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null);
    startManagingCursor(mCursor);

    ListAdapter adapter = new SimpleCursorAdapter(this,
            R.layout.row,
            mCursor, 
            new String[] { Phones.NAME, Phones.NUMBER}, 
            new int[] { R.id.text_name, R.id.text_phone });
    setListAdapter(adapter);
    getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}

The result kind of looks like what I want, but it looks like the list doesn't know which item of it is selected. Also, I need to click exactly on the CheckBox. In the List11 example, I only need to click on the item row.

So what do I need to do to make a multiple choice list with my custom view for each row? Many thanks.

Sufian
  • 5,997
  • 14
  • 60
  • 111
Phil
  • 5,370
  • 5
  • 32
  • 55
  • Did you find out the answer to this one? an example maybe? I have the same question :) http://stackoverflow.com/questions/3858501/multiple-choice-list-without-checkboxes-on-a-custom-view – Lior Iluz Oct 04 '10 at 20:12
  • 1
    So was there any solution ? I am stuck on same problem. – Pritam Dec 20 '10 at 12:54

9 Answers9

17

You have to make your own RelativeLayout that implements the Checkable interface and have a reference to the CheckBox or to the CheckedTextView (or a list if it's multiple choice mode).

Look at this post: http://www.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/

Sufian
  • 5,997
  • 14
  • 60
  • 111
Fernando Gallego
  • 3,974
  • 27
  • 50
  • 1
    Link posted solves also issues when the user directly click on the checkbox – Rainbowbreeze Sep 04 '11 at 22:50
  • 3
    The tutorial is good, but it is missing an important part: how can you handle list item clicks in the Activity that holds the ListView so that you can show up a contextual action bar for example? – Konsumierer May 15 '12 at 10:10
  • @ferdy182 Post you're referring to is not available anymore. Can you please provide copy of article (or code at least) ? Thanks – Marek Sebera Nov 20 '12 at 16:04
  • 1
    @MarekSebera you can find the cached version here but it would be a nice idea to copy it elsewhere http://web.archive.org/web/20101105004007/http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/ – Fernando Gallego Nov 21 '12 at 09:33
7

The answer of Rahul Garg is good for the first time the list is loaded, if you want some rows to be checked depending on the model data, but after that you have to handle the check/uncheck events by yourself.

You can override the onListItemCLick() of the ListActivity to check/uncheck the rows

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    ViewGroup row = (ViewGroup)v;
 CheckBox check = (CheckBox) row.findViewById(R.id.checkbox);            
    check.toggle();
}

If you do so, do not set the ListView to CHOICE_MODE_MULTIPLE, because it makes strange things when calling the function.

To retrieve the list of checked rows, you have to implement a method yourself, calling getCheckItemIds() on the ListView does not work:

ListView l = getListView();
int count = l.getCount();
for(int i=0; i<count; ++i) {
   ViewGroup row = (ViewGroup)l.getChildAt(i);
   CheckBox check = (Checked) row.findViewById(R.id.ck1);
   if( check.isChecked() ) {
      // do something
   }
}
Shan Xeeshi
  • 1,468
  • 16
  • 24
JVitela
  • 2,432
  • 2
  • 20
  • 18
5

The solution is to create a custom View that implements the Clickable interface.

public class OneLineCheckableListItem extends LinearLayout implements Checkable {

    public OneLineCheckableListItem(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private boolean checked;


    @Override
    public boolean isChecked() {
        return checked;
    }

    @Override
    public void setChecked(boolean checked) {
        this.checked = checked; 

        ImageView iv = (ImageView) findViewById(R.id.SelectImageView);
        iv.setImageResource(checked ? R.drawable.button_up : R.drawable.button_down);
    }

    @Override
    public void toggle() {
        this.checked = !this.checked;
    }
}

And create a custom layout for the list items using the new widget.

<?xml version="1.0" encoding="utf-8"?>
<ax.wordster.OneLineCheckableListItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="4dp"
    android:background="@drawable/selector_listitem"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/SelectImageView"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/button_friends_down" />

    <TextView
        android:id="@+id/ItemTextView"
        android:layout_width="fill_parent"
        android:layout_height="60dp"
        android:gravity="center"
        android:text="@string/___"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="@color/text_item" />

</ax.wordster.OneLineCheckableListItem>

Then create a new custom Adapter using the layout above.

Adorjan Princz
  • 11,208
  • 3
  • 32
  • 25
  • Could you help me: how to make multiple selection not on item click, but on ImageView in itemView and in onItemClick I could make some other action ? – DavyJonesUA May 13 '13 at 09:45
  • my condition is weird, setChecked is not called at all, but AbsListView.MultiChoiceModeListener#onItemCheckedStateChanged is called – HendraWD Jan 12 '16 at 10:23
5

Each such view has a TextView and a CheckBox.

No, it doesn't. It has a CheckedTextView.

So what do I need to do to make a multiple choice list with my custom view for each row?

Try making the CheckBox android:id value be "@android:id/text1" and see if that helps. That is the ID used by Android for the CheckedTextView in simple_list_item_multiple_choice.

CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • 1
    Thanks CommonsWare. I just tried that and that didn't work for me. Btw, where do I look for the implementation of android.R.simple_list_item_multiple_choice? I can't find the xml file with that name in ApiDemos. – Phil Apr 16 '10 at 16:07
  • 2
    It's not in ApiDemos, it's in the SDK. All of the SDK resources reside in `$ANDROID_SDK/platforms/$VERSION/data/res`, where `$ANDROID_SDK` is wherever you installed the SDK and `$VERSION` is some Android version (e.g., `android-2.1`). – CommonsWare Apr 16 '10 at 16:24
  • 1
    Thanks. I've checked out the content of simple_list_item_multiple_choice. What I found out is it works if the View for each row is just . Once I wrap around it with a Layout, things won't work anymore. I don't know how to cram in one more view to display another piece of text. – Phil Apr 17 '10 at 09:00
  • 1
    Ah. Well, then you are probably stuck managing it all yourself. Here is an example of a list that has a RatingBar and a TextView, with the state of the RatingBar maintained as you scroll: http://github.com/commonsguy/cw-android/tree/master/FancyLists/RateList/ -- the same technique can be adapted for your own checkbox. – CommonsWare Apr 17 '10 at 10:49
1

Simple example how to get a custom layout to work as custom checkbox:

private class FriendsAdapter extends ArrayAdapter<WordsterUser> {
    private Context context;

    public FriendsAdapter(Context context) {
        super(context, R.layout.listitem_oneline);

        this.context = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int pos = position;

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View rv = inflater.inflate(R.layout.listitem_oneline, parent, false);
        rv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean checked = friendsListView.isItemChecked(pos); 
                friendsListView.setItemChecked(pos, !checked);
            }
        });

        WordsterUser u = getItem(position);

        TextView itw = (TextView) rv.findViewById(R.id.ItemTextView);
        itw.setText(u.userName + " (" + u.loginName + ")");

        ImageView iv = (ImageView) rv.findViewById(R.id.SelectButton);

        if (friendsListView.isItemChecked(position)) {
            iv.setImageResource(R.drawable.downbutton);
        } else {
            iv.setImageResource(R.drawable.upbutton);
        }

        return rv;
    }
}
Adorjan Princz
  • 11,208
  • 3
  • 32
  • 25
1

I found it very useful this little code: http://alvinalexander.com/java/jwarehouse/apps-for-android/RingsExtended/src/com/example/android/rings_extended/CheckableRelativeLayout.java.shtml

It is a great addition to @ferdy182 's http://www.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/ content.

russellhoff
  • 1,599
  • 3
  • 26
  • 56
  • Alvin Alexander's CheckableRelativeLayout makes the top level view of the row checkable, including a proper drawable state android.R.attr.state_checked. Child drawables like Checkbox can make use of that state if you pass the state down to them. You have to apply android:duplicateParentState="true" to every child of CheckableRelativeLayout including the Checkbox. – dschulten Sep 05 '15 at 06:54
1

It is possible by some trick

in your ListActivtyClass in method

protected void onListItemClick(ListView l, View v, int position, long id) {
//just set
<your_model>.setSelected(true);
}

now in you custom Adapter

public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(textViewResourceId, parent, false);
        }       
        if (<your_model>.isSelected()) {
            convertView.setBackgroundColor(Color.BLUE);
        } else {
            convertView.setBackgroundColor(Color.BLACK);
        }
        return convertView;
    }

this way you can customize the view in adapter when the item is selected in the list.

Marek Sebera
  • 37,155
  • 34
  • 153
  • 231
Rahul Garg
  • 7,950
  • 8
  • 30
  • 28
0

Got the solution ... You can get the clicks on the views (like checkboxes in custom layouts of row) by adding listener to each of them in the adapter itself while you return the converted view in getView(). You may possibly have to pass a reference of list object if you intent to get any list specific info. like row id.

Pritam
  • 2,147
  • 5
  • 33
  • 50
0

I want to confirm that the Pritam's answer is correct. You need an onClickListener on each list's item (define it in the adapter's getView()).

You can create a new onClickListener() for each item, or have the adapter implement onClickListener() - in this case the items must be tagged for the listener to know, which item it is operating on.

Relying on the list onItemClickListener() - as someone advised in another thread - will not work as the CheckBox will intercept the click event so the list will not get it.

And finally @Rahul and JVitella:

The situation is that the CheckBox on a list item must be clickable and checkable independently from the list item itself. Therefore the solution is as I just described above.

Sufian
  • 5,997
  • 14
  • 60
  • 111
Yar
  • 4,535
  • 2
  • 32
  • 40