Multiple choice list with custom view?
Asked Answered
S

9

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.

Shavonneshaw answered 16/4, 2010 at 10:17 Comment(2)
Did you find out the answer to this one? an example maybe? I have the same question :) #3859001Nootka
So was there any solution ? I am stuck on same problem.Tegan
A
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/

Acariasis answered 17/2, 2011 at 17:32 Comment(4)
Link posted solves also issues when the user directly click on the checkboxPeptize
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?Tenth
@ferdy182 Post you're referring to is not available anymore. Can you please provide copy of article (or code at least) ? ThanksArgali
@MarekSebera you can find the cached version here but it would be a nice idea to copy it elsewhere web.archive.org/web/20101105004007/http://www.marvinlabs.com/…Acariasis
J
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
   }
}
Jylland answered 19/1, 2011 at 14:45 Comment(0)
W
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.

Wrestle answered 16/4, 2010 at 12:49 Comment(4)
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.Shavonneshaw
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).Wrestle
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 <CheckedTextView>. 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.Shavonneshaw
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: github.com/commonsguy/cw-android/tree/master/FancyLists/… -- the same technique can be adapted for your own checkbox.Wrestle
S
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.

Sihun answered 8/2, 2013 at 19:48 Comment(2)
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 ?Blais
my condition is weird, setChecked is not called at all, but AbsListView.MultiChoiceModeListener#onItemCheckedStateChanged is calledChios
A
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.

Alan answered 22/11, 2010 at 17:5 Comment(0)
S
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;
    }
}
Sihun answered 8/2, 2013 at 17:41 Comment(1)
In your example, how does the FriendsAdapter instance know what friendsListView is referencing?Bullace
L
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.

Luger answered 22/12, 2014 at 10:33 Comment(1)
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.Confidence
T
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.

Tegan answered 20/12, 2010 at 13:35 Comment(0)
F
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.

Ferryman answered 9/2, 2011 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.