Android 通过自定义选择器的 ListView 项目背景

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2562051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:19:34  来源:igfitidea点击:

ListView item background via custom selector

androidlistview

提问by shilgapira

Is it possible to apply a custom background to each Listview item via the list selector?

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

The default selector specifies @android:color/transparentfor 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 answerthat this is possible.

默认选择器@android:color/transparentstate_focused="false"案例指定,但将其更改为某些自定义可绘制对象不会影响未选择的项目。Romain Guy 似乎在这个答案中暗示这是可能的。

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!

在此先感谢您的帮助!

回答by dgmltn

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 listSelectorof your list:

我自己对此感到沮丧,终于解决了。正如 Romain Guy 暗示的"android:state_selected"那样,您必须使用另一个状态。为列表项的背景使用可绘制状态,并为列表使用不同的可绘制状态listSelector

list_row_layout.xml:

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:

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 的 layout.xml:

...
<ListView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:listSelector="@drawable/listitem_selector"
   />
...

listitem_selector.xml:

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>

回答by Micha? K

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.

当您有一个以填充为背景的 9-patch drawable 时,dglmtn 的解决方案不起作用。奇怪的事情发生了,我什至不想谈论它,如果你有这样的问题,你知道他们。

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:

现在,如果您想拥有一个具有不同状态和 9 块可绘制对象的列表视图(我认为它可以与任何可绘制对象和颜色一起使用),您必须做两件事:

  1. Set the selector for the items in the list.
  2. Get rid of the default selector for the list.
  1. 为列表中的项目设置选择器。
  2. 摆脱列表的默认选择器。

What you should do is first set the row_selector.xml:

你应该做的是首先设置 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_focusedfor the list, but it's applied for the list item.

不要忘记android:state_selected. 它适用android:state_focused于列表,但适用于列表项。

Now apply the selector to the items (row.xml):

现在将选择器应用于项目 (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.

这应该做的事情。

回答by cV2

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

永远不要为您的列表视图行使用“背景颜色”...

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

这将阻止每个选择器操作(是我的问题!)

good luck!

祝你好运!

回答by Scott D. Strader

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

Android 开发者博客中的文章“为什么我的列表是黑色的?Android 优化”对滚动时列表背景变黑的原因进行了详尽的解释。简单的答案:将列表中的 cacheColorHint 设置为透明 (#00000000)。

回答by Cabezas

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

就足够了,如果你输入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:

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>

回答by pengwang

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

my_selector 是您想要的自定义选择器 对不起,我不知道如何编写我的代码

回答by Butters

instead of:

代替:

android:drawable="@color/transparent" 

write

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

回答by CommonsWare

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.

但是,您可以控制选择更改并绘制您想要的任何内容。在这个示例项目中,我使选择器透明并在所选项目上绘制一个条。

回答by Apperside

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

并在 ListView 上设置(这对于使其工作非常重要)属性

android:choiceMode="singleChoice"

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

对于 textColor 只需放入颜色文件夹(重要,不可绘制文件夹!)这样的选择器

<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

没有繁琐的解决方法,一切都可以正常工作。希望这有帮助

回答by Gubatron

FrostWire Team over here.

FrostWire 小队这边。

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.

所有的选择器废话 api 都没有按预期工作。在尝试了该线程中提供的所有解决方案后,我们刚刚解决了膨胀 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;
    }
    
  1. 确保您的项目保持其状态,我们将其作为 MenuItem 的成员变量(选择布尔值)

  2. 当您膨胀时,询问是否选择了底层项目,如果是,只需将您想要的可绘制资源设置为背景(无论是 9patch 还是其他)。确保您的适配器意识到这一点,并且在选择了某些内容时它会调用 notifyDataChanged()。

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

如果选择器真的可以工作,那就太好了,理论上这是一个不错的优雅解决方案,但它似乎坏了。吻。