Is it possible to apply a custom background to each Listview item via the list selector?
The default selector specifies @android:color/transparent
for the state_focused="false"
case, but changing this to some custom drawable doesn't affect items that aren't selected. Romain Guy seems to suggest in this answer that this is possible.
I'm currently achieving the same affect by using a custom background on each view and hiding it when the item is selected/focused/whatever so the selector is shown, but it'd be more elegant to have this all defined in one place.
For reference, this is the selector I'm using to try and get this working:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false"
android:drawable="@drawable/list_item_gradient" />
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
<item android:state_focused="true" android:state_enabled="false"
android:state_pressed="true"
android:drawable="@drawable/list_selector_background_disabled" />
<item android:state_focused="true" android:state_enabled="false"
android:drawable="@drawable/list_selector_background_disabled" />
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="true"
android:drawable="@drawable/list_selector_background_focus" />
</selector>
And this is how I'm setting the selector:
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:listSelector="@drawable/list_selector_background" />
Thanks in advance for any help!
I've been frustrated by this myself and finally solved it. As Romain Guy hinted to, there's another state, "android:state_selected"
, that you must use. Use a state drawable for the background of your list item, and use a different state drawable for listSelector
of your list:
list_row_layout.xml:
<?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="?android:attr/listPreferredItemHeight"
android:background="@drawable/listitem_background"
>
...
</LinearLayout>
listitem_background.xml:
<?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/android:transparent" />
<item android:drawable="@drawable/listitem_normal" />
</selector>
layout.xml that includes the ListView:
...
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:listSelector="@drawable/listitem_selector"
/>
...
listitem_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/listitem_pressed" />
<item android:state_focused="true" android:drawable="@drawable/listitem_selected" />
</selector>
The solution by dglmtn doesn't work when you have a 9-patch drawable with padding as background. Strange things happen, I don't even want to talk about it, if you have such a problem, you know them.
Now, If you want to have a listview with different states and 9-patch drawables (it would work with any drawables and colors, I think) you have to do 2 things:
What you should do is first set the row_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_enabled="true"
android:state_pressed="true" android:drawable="@drawable/list_item_bg_pressed" />
<item android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/list_item_bg_focused" />
<item android:state_enabled="true"
android:state_selected="true" android:drawable="@drawable/list_item_bg_focused" />
<item
android:drawable="@drawable/list_item_bg_normal" />
</selector>
Don't forget the android:state_selected
. It works like android:state_focused
for the list, but it's applied for the list item.
Now apply the selector to the items (row.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/row_selector"
>
...
</RelativeLayout>
Make a transparent selector for the list:
<ListView
android:id="@+id/android:list"
...
android:listSelector="@android:color/transparent"
/>
This should do the thing.
Never ever use a "background color" for your listview rows...
this will block every selector action (was my problem!)
good luck!
The article "Why is my list black? An Android optimization" in the Android Developers Blog has a thorough explanation of why the list background turns black when scrolling. Simple answer: set cacheColorHint on your list to transparent (#00000000).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With