how to set choice mode single for listview with images

The recommended solution here is to rely on built-in ListView’s selection support specifying single-choice mode for it:

list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

Then you should let your list item to implement to implement Checkable interface; that requires some customization of the root view of your layout. Assuming that it has LinearLayout as a root, an implementation may look like:

public class MyListItem extends LinearLayout implements Checkable {

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

    public MyListItem(Context context) {
        super(context);
    }

    private boolean checked = false;

    private ImageView icon;

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        icon = (ImageView)findViewById(R.id.img); // optimisation - you don't need to search for image view every time you want to reference it
    }
    @Override
    public boolean isChecked() {
        return checked;
    }

    @Override
    public void setChecked(boolean checked) {
        this.checked = checked;
        if (icon.getVisibility() == View.VISIBLE) {
            icon.setImageResource((checked) ? R.drawable.checked : R.drawable.unchecked);
        }
    }

    @Override
    public void toggle() {
        setChecked(!checked);
    }
}

Your layout file should be updated to reference MyListItem class instead of LinearLayout too, of course.

This may be a somewhat difficult approach, but it has benefits like restoring checked item automatically when activity is recreated.

Another option is to use the list’s choice mode again and override adapter’s getView to know if the item is checked and update image accordingly:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final ListView list = getListView();
    list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    list.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item,
            R.id.title, text) {
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = super.getView(position, convertView, parent);
            ImageView icon = (ImageView) v.findViewById(R.id.img);
            if (list.isItemChecked(position)) {
                icon.setImageResource(R.drawable.checked);
            } else {
                icon.setImageResource(R.drawable.unchecked);
            }
            return v;
        }
    });
}

However this version has some performance issues – findViewById and setImageResource are relatively time-consuming operations so you should consider using some caching. I recommend to watch “The world of ListView” video to learn some very useful tips about this widget.

The latter approach also ties adapter to the listview which introduces unnecessary coupling.

Leave a Comment