Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView Item Selected State not working

So I have a ListView and I want to change the color of each items background and text. This ListView is inside a ListFragment. My code inflates the layout in the onCreateView and inflates the layout of each item in the newView.

The android:state_pressed="true" is working fine, whenever I press in one item the background changes to that color. But when selecting an item neither the bg color or text color changes, even though I've defined an item with android:state_selected="true" in the selector.

Edit: I'm using SDK level 11 (Android 3.0) and a Motorola Xoom.

The list fragment layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>
</LinearLayout>

The list item layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="25dp"
    android:background="@drawable/list_item_bg_selector">
    <TextView android:id="@+id/form_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="@dimen/text_size_xlarge"
        android:textStyle="bold"
        android:textColor="@drawable/list_item_text_selector" />
    <TextView android:id="@+id/form_subtitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="@dimen/text_size_medium"
        android:textStyle="normal"
        android:layout_marginTop="5dp"
        android:textColor="@drawable/list_item_text_selector" />
</LinearLayout>

The background selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:state_pressed="true"
        android:drawable="@color/white" />
    <item
        android:state_selected="true"
        android:drawable="@drawable/list_item_bg_selected" />
    <item 
        android:drawable="@color/list_bg" />
</selector>

The text selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_selected="true"
        android:drawable="@color/white" />
    <item 
        android:drawable="@color/list_text_blue" />
</selector>
like image 486
aromero Avatar asked Jun 01 '11 17:06

aromero


3 Answers

The answer is to use the android:state_activated="true" state, instead of the "selected" state. More on this here: ListFragment Item Selected Background

like image 82
aromero Avatar answered Nov 14 '22 04:11

aromero


The best solution with support of all API levels is to implement Checkable feature for list item View which means that the top view of your list item layout has to implement Checkable interface (in my case it was TextView, but the same can be applied on ViewGroup classes like LinearLayout). When you click on a list item, the ListView call setChecked method and there we change the state of View to use android:state_checked="true" selector. Together with list view android:choiceMode="singleChoice" it will select only one item.

The trick is to override onCreateDrawableState method and set the checked state here for drawables. See example of SelectableTextView bellow. After the setChecked is called, the checked state is stored and called refreshDrawableState.

Example of SelectableTextView:

package com.example.widget.SelectableTextView;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.TextView;

public class SelectableTextView extends TextView implements Checkable {
    private static final int[] CHECKED_STATE_SET = {
                    android.R.attr.state_checked
    };

    private boolean mChecked;

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

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

    public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setChecked(boolean checked) {
        if (mChecked != checked) {
            mChecked = checked;
            refreshDrawableState();
        }
    }

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

    @Override
    public void toggle() {
        setSelected(!mChecked);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        }
        return drawableState;
    }
}

Example of selectable_list_item.xml layout:

<?xml version="1.0" encoding="utf-8"?>
<com.example.widget.SelectableTextView xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:id="@android:id/text1"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:textColor="@color/list_item_selector_foreground"
          android:background="@drawable/list_item_selector_background"
          tools:text="Item 1"/>

Example of list_item_selector_foreground.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- checked -->
    <item android:color="@color/list_item_text_active" android:state_checked="true"/>

    <item android:color="@color/list_item_text"/>
</selector>

Example of list_item_selector_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/list_item_background_selected" android:state_pressed="true"/>
    <item android:drawable="@color/list_item_background_selected" android:state_focused="true"/>
    <item android:drawable="@color/list_item_background_active" android:state_checked="true"/>

    <item android:drawable="@color/list_item_background"/>
</selector>
like image 42
Arcao Avatar answered Nov 14 '22 04:11

Arcao


Do not forget to set clickable="true" for the layout. This solved my problem.

List item layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/list_item_bg_selector"
        android:clickable="true" >

        <TextView
            android:id="@+id/tvNewsPreviewTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxLines="3"
            android:ellipsize="end"
            android:textSize="@dimen/news_preview_title_textsize"
            android:textStyle="bold" />
    </RelativeLayout>

Background selector:

 <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true" >
            <shape android:shape="rectangle">
                <stroke android:width="1dp" android:color="@color/black" />
                <gradient android:startColor="@color/white" android:endColor="@color/white" />
            </shape>
        </item>
        <item>
            <shape android:shape="rectangle">
                <stroke android:width="1dp" android:color="@color/holo_gray_darker" />
                <gradient android:startColor="@color/holo_gray_bright" android:endColor="@color/holo_gray_bright" />
            </shape>
        </item>
    </selector>
like image 1
Yunus Emre INCE Avatar answered Nov 14 '22 04:11

Yunus Emre INCE