通过自定义选择器查看项背景

是否可以通过列表选择器对每个 Listview 项应用自定义背景?

默认的选择器为 state_focused="false"指定了 @android:color/transparent,但是将其更改为某种自定义绘制并不影响未选中的项。罗曼似乎暗示 在这个答案中这是可能的。

我目前正在通过在每个视图上使用自定义背景,并在选择/聚焦/任何情况下隐藏它来实现同样的效果,以便显示选择器,但是如果在一个地方全部定义这个背景会更加优雅。

作为参考,这是我用来尝试让这个工作的选择器:

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

这就是我设置选择器的方法:

<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:listSelector="@drawable/list_selector_background" />

提前谢谢你的帮助!

155242 次浏览

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.

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

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>

instead of:

android:drawable="@color/transparent"

write

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

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

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.

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

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

good luck!

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.

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

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>