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


98

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

默认选择指定@android:color/transparentstate_focused="false"情况下,但改变这一些自定义绘制不影响未选定的项目。罗曼·盖伊(Romain Guy)似乎在此答案中暗示这是可能的。

我目前正在通过在每个视图上使用自定义背景并在选择/聚焦/以任何方式显示项目时隐藏它来实现相同的效果,但是将所有这些都定义在一个位置会更加优雅。

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

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

在此先感谢您的帮助!

Answers:


128

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

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>

包含ListView的layout.xml:

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

1
感谢您的深入回应。正如我在问题中提到的那样,这正是我目前正在做的事情,并且效果很好。
shilgapira

不幸的是,自定义列表视图仍然遇到问题。我在这里发布了我的具体问题:stackoverflow.com/questions/5426385/… ; 我会很感激您的任何投入。
LostNomad11年

当您使用带有填充的9修补程序可绘制对象作为背景时,它不起作用。我找到最终的解决办法,我想,看到我的答案
米哈尔ķ

这适用于后ICS,但对于Gingerbread,整个列表都使用按下或选定的可绘制对象进行着色。
2013年

ICS之前有解决方案吗?
Lonli-Lokli

78

当您有一个9色可绘制的可填充背景为背景的图形时,dglmtn的解决方案不起作用。发生奇怪的事情,我什至不想谈论它,如果您有这样的问题,您就会知道。

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

  1. 设置列表中项目的选择器。
  2. 摆脱列表的默认选择器。

首先应该设置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>

别忘了android:state_selected。它的工作方式类似于android:state_focused列表,但适用于列表项。

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

为列表创建一个透明的选择器:

<ListView
    android:id="@+id/android:list"
    ...
    android:listSelector="@android:color/transparent"
    />

这应该做的事情。


1
+1,我之前没有看到您的答案,我碰到了相同的结果,我自己做了。但是,感谢您提到9补丁可绘制对象,我相信它在将来的实现中可能会有用。这应该是最好的答案,因为此方法更干净且可维护。
IsaacCisneros

28
很抱歉,但是这种事情使人们有时想起为什么这些该死的UI api太烂了。Android仍有很多工作要做。这样的基本事物不应该是PITA。
Gubatron 2012年

2
+1谢谢,谢谢,谢谢。跳过所有这些步骤,以实现如此基本的目标。所有这些状态是如此令人困惑。
莫里茨

3
代替android:listSelector =“ @ drawable / list_selector”,只需编写android:listSelector =“ @ android:color / transparent”。不需要额外的list_selector.xml。
Sofi Software LLC 2013年

1
正确,非破坏性列表选择器可以只是@android:color / transparent而不是您自己的xml选择器。刚刚尝试过。不起作用的是@ null,这使我感到惊讶,因为它应该指出:“无列表选择器”,并且在该项目后面绘制了列表选择器时,不应绘制任何内容。但这不起作用,默认选择器又返回了……
Zordid 2014年

17

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

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

祝好运!


3
这不是真的。只需使用一个选择作为背景,而不是一个静态的颜色或绘制
米哈尔ķ

这原意是“背景色”。完全接受你的话。
cV2 2014年

我到达这里是因为我现在需要一个选择器来使用setBackgroundColor“颜色”。叹...使用setBackgroundsetBackgroundDrawable根据您的API版本使用选择器。
EpicPandaForce'5

5

Android开发者博客中的文章“为什么我的列表为什么变黑?Android优化”有一个详尽的解释,说明了滚动时列表背景为什么变黑。简单答案:将列表上的cacheColorHint设置为透明(#00000000)。


1
一种示例性的简单性,但效果很好。感谢Romain Guy ... <ListView ... android:cacheColorHint =“#00000000”> </ ListView>全部!
EricJOYÉ2014年

不用谢罗曼·盖伊(Romain Guy)。他是问题的一部分。在这样的操作系统中,不应有太多的“隐藏技巧”或其他黑客手段。即使我喜欢Android,但与其他SDK(甚至是较新/较不成熟的SDK)相比,它也是一大堆垃圾。
StackOverflowed 2015年

5

如果您输入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>

2
很棒...最简单的例子
Shihab Uddin

1
并使列表视图选择器透明
Sayka 2015年

4

代替:

android:drawable="@color/transparent" 

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

4

您可以编写一个主题:

<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是您要自定义选择器的方法,对不起,我不知道如何编写代码


感谢您的帮助,但这不能直接通过选择器设置默认列表项背景。
shilgapira 2010年

2

我不确定如何通过选择器本身实现所需的效果-毕竟,按照定义,整个列表只有一个选择器。

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


实际上,完全只有一个选择器是完全有意义的。我想我(或曾经)<item android:state_focused="false" android:drawable="@android:color/transparent" />对默认选择器中子句的存在感到困惑。
shilgapira

马克,玩耍(与吉尔有同样的问题),我尝试了您的解决方案,它仅部分用于轨迹球,当您仅使用触摸来触摸项目并且触发了onItemClicked时,noesSeelected会被调用,如果您想要这种东西,很可能您必须跟踪ListView中的选定位置和按下位置,并在Item本身(使其自定义View)和ListView的dispatchDraw中绘制所需的内容。
codeScriber

@codeScriber:“当您仅使用touch触摸项目并触发onItemClicked时,nothingSeelected不会被调用” –这是完全正常的行为,因为touch与选择无关。
CommonsWare

2

我总是使用相同的方法,并且它每次都可以在任何地方使用:我只是使用这样的选择器

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

并在ListView上设置(这很重要)

android:choiceMode="singleChoice"

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

这是一个示例行模板

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

没有繁琐的解决方案,所有工作都可以正常进行。希望这个帮助


-3

FrostWire团队在这里。

所有选择器废话api均无法正常工作。在尝试了该线程中提出的所有解决方案后,我们只是在膨胀ListView Item时解决了该问题。

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

如果选择器可以正常工作,那将是非常不错的选择,从理论上讲,这是一个很好的解决方案,但是看起来好像坏了。吻。


我想尝试此解决方案,能否请您提供更多详细说明或完整的解决方案?谢谢
Andrew Lam
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.