Search code examples
androidlistviewselectorandroid-2.3-gingerbread

setItemChecked not working on Gingerbread


I am using the following selector to change the appearance of text in a listView item:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true"
          android:color="#FFFFFFFF" /> <!-- checked -->
    <item android:state_activated="true"
          android:color="#FFFFFFFF" /> <!-- activated -->
    <item android:state_pressed="true"
          android:color="#FFFFFFFF" /> <!-- pressed -->
    <item android:state_focused="true"
          android:color="#FFFFFFFF" /> <!-- focused -->
    <item android:color="#FF000000" /> <!-- default -->
</selector>

The entire selector works fine on later versions of Android (ICS, JB), but on Gingerbread, while the pressed_state item is being applied correctly, when I call setItemChecked on the listView, the state_checked item isn't applied.

The code I am using to set the item is as follows:

@Override
protected void onResume()
{
    super.onResume();

    getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    for (int index = 0; index < measureList.size(); index++)
    {
        if (measureList.get(index).getId() == appContext.getMeasureId())
        {
            getListView().setItemChecked(index, true);
        }
    }
}

and the xml used to set the selector is this:

<TextView
        android:id="@+id/item_text"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:layout_marginTop="8dp"
        android:layout_marginLeft="8dp"
        android:paddingRight="10dp"
        android:ellipsize="end"
        android:layout_toRightOf="@id/item_thumb"
        android:maxLines="1"
        android:scrollHorizontally="true"
        android:textStyle="bold"
        android:textSize="16sp"
        android:textColor="@color/selected_text_selector"
        />

Does anyone know why this happens? I haven't yet tested it out on versions of Android between GB and ICS, but will edit this post as soon as I do.


Solution

  • After a little searching, it seems to me the reason that the state_checked isn't expressed pre-Honeycomb is the fact that the setActive method on View is not available before API level 11. This means that the checked state is not propagated to the child views of my layout.

    THE KEY:

    1. Swap the TextView for a CheckedTextView
    2. Propagate the checked state from the parent view to the children

    1) Was a simple switch in the XML, and for 2) I modified the code in the answer linked to by Voicu to give the following:

    public class CheckableRelativeLayout extends RelativeLayout implements Checkable
    {
        private boolean checked = false;
    
        public CheckableRelativeLayout(Context context) {
            super(context, null);
        }
    
        public CheckableRelativeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        private static final int[] CheckedStateSet = {
                R.attr.state_checked
        };
    
        @Override
        protected void dispatchSetPressed(boolean pressed)
        {
            super.dispatchSetPressed(pressed);
            setChecked(pressed);
        }
    
        @Override
        public void setChecked(boolean checked) {
            this.checked = checked;
            for (int index = 0; index < getChildCount(); index++)
            {
                View view = getChildAt(index);
                if (view.getClass().toString().equals(CheckedTextView.class.toString()))
                {
                    CheckedTextView checkable = (CheckedTextView)view;
                    checkable.setChecked(checked);
                    checkable.refreshDrawableState();
                }
            }
            refreshDrawableState();
        }
    
        public boolean isChecked() {
            return checked;
        }
    
        public void toggle() {
            checked = !checked;
            refreshDrawableState();
        }
    
        @Override
        protected int[] onCreateDrawableState(int extraSpace) {
            final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
            if (isChecked()) {
                mergeDrawableStates(drawableState, CheckedStateSet);
            }
            return drawableState;
        }
    
        @Override
        public boolean performClick() {
            return super.performClick();
        }
    }