By shilgapira


2010-04-01 16:44:42 8 Comments

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!

10 comments

@pengwang 2010-04-02 07:52:48

You can write a theme:

<pre>

    android:name=".List10" android:theme="@style/Theme"

theme.xml

<style name="Theme" parent="android:Theme">
        <item name="android:listViewStyle">@style/MyListView</item>
</style>

styles.xml

 <style name="MyListView" parent="@android:style/Widget.ListView">
<item name="android:listSelector">@drawable/my_selector</item>

my_selector is your want to custom selector I am sorry i donot know how to write my code

@shilgapira 2010-04-06 09:48:00

Thanks for the help, but this doesn't directly help in setting the default listitem background via the selector.

@Cabezas 2015-04-06 21:43:32

It's enough,if you put in list_row_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/listitem_background">... </LinearLayout>

listitem_selector.xml:

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

@Shihab Uddin 2015-11-30 11:11:47

awesome...simplest example

@Sayka 2015-12-03 20:06:30

And also make the listview selector transparent

@dgmltn 2010-05-13 23:44:09

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>

@shilgapira 2010-05-16 09:46:08

Thanks for the in-depth response. As I mentioned in my question, this is exactly what I'm doing at the moment as well and it works quite well.

@LostNomad311 2011-03-24 22:38:18

Unfortunately, I am still having problems customizing my list view. I posted my specific issues here: stackoverflow.com/questions/5426385/… ; I would appreciate any input you may have.

@Michał K 2012-05-08 14:57:03

It doesn't work when you use 9-patch drawables with padding as background. I found the ultimate solution, I think, see my answer

@gunar 2013-08-09 13:13:47

This works for post-ICS, but for Gingerbread the whole list is colored with pressed or selected drawable.

@Lonli-Lokli 2014-04-07 12:03:44

Is there any solution for pre-ICS?

@Roel 2014-12-15 15:21:19

This doesn't work either. Nothing works. Now I get no background. I have the choise a blue holo background if selected or nothing.

@Ram 2015-03-31 07:19:36

it work on 4.2 but not in 2.3 listitem_selector.xml cover whole listview item

@Apperside 2015-02-12 11:04:27

I always use the same method and it works every time, every where: I simply use a selector like this

<item android:state_activated="true"  android:color="@color/your_selected_color" />
<item android:state_pressed="true" android:color="@color/your_pressed_color" />
<item android:color="@color/your_normal_color"></item>

and set on the ListView (THIS IS VERY IMPORTANT TO MAKE IT WORKING) the attribute

android:choiceMode="singleChoice"

for the textColor just put in the color folder(IMPORTANT, not drawable folder!) a selector like this

<item android:state_activated="true"  android:color="@color/your_selected_textColor" />
<item android:state_pressed="true" android:color="@color/your_pressed_textColor" />
<item android:color="@color/your_normal_textColor"></item>

this a sample row template

<ImageView
    android:id="@+skinMenu/lblIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:src="@drawable/menu_catalog" />

<TextView
    android:id="@+skinMenu/lblTitle"
    style="@style/superlabelStyle"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_marginLeft="20dp"
    android:gravity="center_vertical"
    android:text="test menu testo"
    android:textColor="@color/menu_textcolor_selector"
    android:textSize="20dp"
    android:textStyle="bold" />

everything showld work without tedious workarounds. hope this help

@Butters 2011-03-21 01:02:36

instead of:

android:drawable="@color/transparent" 

write

android:drawable="@android:color/transparent"

@Michał K 2012-05-08 15:06:58

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:

  1. Set the selector for the items in the list.
  2. Get rid of the default selector for the list.

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.

@IsaacCisneros 2012-07-30 13:53:41

+1, I didn't see your answer before, I came across the same result doing it on my own. But thanks for mentioning about the 9-patch drawables I'm sure it could be useful in my future implementations. This should be the best answer because this method is cleaner and maintainable.

@Gubatron 2012-09-11 20:21:59

I'm sorry, but this is the kind of things that make think sometimes why do these damn UI apis have to be so crappy. Android still has a lot to go through. Such basic things shouldn't be such a PITA.

@Moritz 2013-01-08 15:36:34

+1 Thank you, thank you, thank you. Jumping through all these hoops to achieve something so basic. All these states are so very confusing.

@Michał K 2013-06-25 12:44:07

It works for many people as you can see. @Gubatron had some problem as well. I think you should post a question with some details on your particular issue (you can link to this answer so it's not marked as duplicate and so I can find it) and maybe we'll figure something out

@Sofi Software LLC 2013-09-30 22:12:15

Instead of android:listSelector="@drawable/list_selector" just write android:listSelector="@android:color/transparent". No need for the extra list_selector.xml.

@Zordid 2014-04-14 14:02:08

Correct, the non-destroying list selector can just be @android:color/transparent instead of your own xml selector. Just tried it. The thing that does not work is @ null, which surprises me because that should state: "no list selector" and as the list selector is drawn behind the item, nothing should be drawn. But that does not work, the default selector is back then...

@tm1701 2015-05-31 10:58:21

In the above solution, the row stays 'selected' when I do a view.setSelected( true). Otherwise is is switching back to the other colour. HOW can I set an initial row selected ... so with the selected colour?

@Gubatron 2012-09-11 20:53:09

FrostWire Team over here.

All the selector crap api doesn't work as expected. After trying all the solutions presented in this thread to no good, we just solved the problem at the moment of inflating the ListView Item.

  1. Make sure your item keeps it's state, we did it as a member variable of the MenuItem (boolean selected)

  2. When you inflate, ask if the underlying item is selected, if so, just set the drawable resource that you want as the background (be it a 9patch or whatever). Make sure your adapter is aware of this and that it calls notifyDataChanged() when something has been selected.

        @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        if (rowView == null) {
            LayoutInflater inflater = act.getLayoutInflater();
            rowView = inflater.inflate(R.layout.slidemenu_listitem, null);
            MenuItemHolder viewHolder = new MenuItemHolder();
            viewHolder.label = (TextView) rowView.findViewById(R.id.slidemenu_item_label);
            viewHolder.icon = (ImageView) rowView.findViewById(R.id.slidemenu_item_icon);
            rowView.setTag(viewHolder);
        }
    
        MenuItemHolder holder = (MenuItemHolder) rowView.getTag();
        String s = items[position].label;
        holder.label.setText(s);
        holder.icon.setImageDrawable(items[position].icon);
    
        //Here comes the magic
        rowView.setSelected(items[position].selected);
    
        rowView.setBackgroundResource((rowView.isSelected()) ? R.drawable.slidemenu_item_background_selected : R.drawable.slidemenu_item_background);
    
        return rowView;
    }
    

It'd be really nice if the selectors would actually work, in theory it's a nice and elegant solution, but it seems like it's broken. KISS.

@Andrew Lam Yat Weng 2016-02-19 11:50:14

I wanna try this solution, could you please give more detail explanation or a complete solution? Thanks

@cV2 2012-06-21 08:57:32

Never ever use a "background color" for your listview rows...

this will block every selector action (was my problem!)

good luck!

@Michał K 2014-07-06 19:12:17

This is not true. Just use a selector as a background, not a static color or drawable

@cV2 2014-07-11 11:10:26

this was intended to be meant by "background color". completely accept your words.

@EpicPandaForce 2015-05-26 15:24:40

I got here because I need a selector now that I've used setBackgroundColor with a "color". Sigh... Use setBackground or setBackgroundDrawable according to your API version with a selector.

@Scott D. Strader 2011-08-06 16:29:39

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).

@Eric JOYÉ 2014-02-12 08:27:29

An exemplary simplicity but it works very well. Thanks for Romain Guy... <ListView ... android:cacheColorHint="#00000000" > </ListView> It's all !

@StackOverflowed 2015-06-08 19:39:00

Don't thank Romain Guy. He's part of the problem. There shouldn't be so many "hidden tricks" or other hacks in an OS like this. Even though I love Android, it is a big steaming pile of dogcrap when compared with other SDKs (even newer/less mature ones!).

@CommonsWare 2010-04-01 17:51:49

I'm not sure how to achieve your desired effect through the selector itself -- after all, by definition, there is one selector for the whole list.

However, you can get control on selection changes and draw whatever you want. In this sample project, I make the selector transparent and draw a bar on the selected item.

@shilgapira 2010-04-06 09:49:56

Indeed, it makes total sense for there to only be at most one selector. I guess I am (or was) a bit confused by the existence of the <item android:state_focused="false" android:drawable="@android:color/transparent" /> clause in the default selector.

@codeScriber 2011-01-19 16:20:47

Mark, playing around (having the same problem as Gil) i tried your solution, it's only partial for track ball only, nothingSeelected is called when you touch items using touch only and onItemClicked is fired, if you want something of that sort, most likely you have to keep track of selected and pressed positions inside the ListView and draw what you need in the Item itself (make it custom View) and in dispatchDraw of the ListView.

@CommonsWare 2011-01-19 16:22:29

@codeScriber: "nothingSeelected is called when you touch items using touch only and onItemClicked is fired" -- this is perfectly normal behavior, since touch has nothing to do with selection.

Related Questions

Sponsored Content

38 Answered Questions

[SOLVED] How to lazy load of images in ListView in Android

11 Answered Questions

[SOLVED] Background ListView becomes black when scrolling

  • 2010-05-14 09:26:26
  • TiGer
  • 89813 View
  • 423 Score
  • 11 Answer
  • Tags:   android listview

2 Answered Questions

[SOLVED] Android ListView selection background

  • 2017-05-09 11:20:55
  • Gaetan L.
  • 537 View
  • 0 Score
  • 2 Answer
  • Tags:   android listview

5 Answered Questions

[SOLVED] how to change font color in selected/focused ListView items?

2 Answered Questions

[SOLVED] ListView item not changing background

  • 2015-05-27 20:21:05
  • ᴘᴀɴᴀʏɪᴏᴛɪs
  • 221 View
  • 0 Score
  • 2 Answer
  • Tags:   android listview

2 Answered Questions

[SOLVED] Android's selector for selected item does not work

3 Answered Questions

[SOLVED] Android ListView State List not showing default item background

2 Answered Questions

[SOLVED] View State lost with click

1 Answered Questions

[SOLVED] Android Selector Problem

Sponsored Content