Фон элемента ListView с помощью пользовательского селектора - PullRequest
97 голосов
/ 01 апреля 2010

Можно ли применить собственный фон к каждому элементу списка через селектор списка?

Селектор по умолчанию указывает @android:color/transparent для случая state_focused="false", но его изменение на некоторые настраиваемые для рисования не влияет на элементы, которые не выбраны. Ромэн Гай, кажется, предлагает в этом ответе , что это возможно.

В настоящее время я достигаю того же эффекта, используя собственный фон для каждого вида и скрывая его, когда элемент выбран / сфокусирован / что угодно, поэтому селектор отображается, но было бы более элегантно, если бы все это было определено одно место.

Для справки, это селектор, который я использую, чтобы попытаться заставить это работать:

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

Заранее спасибо за любую помощь!

Ответы [ 10 ]

128 голосов
/ 14 мая 2010

Я был разочарован этим сам и наконец решил это. Как намекнул Ромейн Гай, есть еще одно состояние, "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>

layout.xml, который включает 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>
78 голосов
/ 08 мая 2012

Решение dglmtn не работает, если у вас есть 9-патч для рисования с отступом в качестве фона. Странные вещи случаются, я даже не хочу об этом говорить, если у вас есть такая проблема, вы их знаете.

Теперь, если вы хотите иметь список с различными состояниями и 9-патчами (я думаю, он будет работать с любыми элементами и цветами), вам нужно сделать 2 вещи:

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

Это должно сработать.

17 голосов
/ 21 июня 2012

Никогда не используйте "цвет фона" для строк списка ...

это заблокирует каждое действие селектора (была моя проблема!)

удачи!

5 голосов
/ 07 апреля 2015

Достаточно, если вы введете 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>
5 голосов
/ 06 августа 2011

Статья "Почему мой список черный? Оптимизация под Android" в блоге разработчиков Android содержит подробное объяснение того, почему фон списка становится черным при прокрутке. Простой ответ: установите cacheColorHint в вашем списке на прозрачный (# 00000000).

4 голосов
/ 21 марта 2011

вместо:

android:drawable="@color/transparent" 

запись

android:drawable="@android:color/transparent"
4 голосов
/ 02 апреля 2010

Вы можете написать тему:

<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 - ваш пользовательский селектор Извините, я не знаю, как написать свой код

2 голосов
/ 12 февраля 2015

Я всегда использую один и тот же метод, и он работает каждый раз, везде, где: Я просто использую селектор вот так

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

все показало работу без утомительных обходных путей. надеюсь, это поможет

2 голосов
/ 01 апреля 2010

Я не уверен, как добиться желаемого эффекта с помощью самого селектора - в конце концов, по определению, есть один селектор для всего списка.

Однако вы можете получить контроль над изменениями выбораи нарисуйте все, что вы хотите.В этом примере проекта я делаю селектор прозрачным и рисую полосу на выбранном элементе.

0 голосов
/ 12 сентября 2012

Команда FrostWire здесь.

Все API селектора дерьма не работают должным образом. После того, как все решения, представленные в этой теме, оказались бесполезными, мы просто решили проблему в момент раздувания элемента ListView.

  1. Убедитесь, что ваш элемент сохраняет свое состояние, мы сделали это в качестве переменной-члена MenuItem (логическое значение выбрано)

  2. Когда вы раздуваетесь, спросите, выбран ли базовый элемент, если это так, просто установите нарисованный ресурс, который вы хотите использовать в качестве фона (будь то 9-патч или что-то еще). Убедитесь, что ваш адаптер знает об этом и вызывает 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;
    }
    

Было бы очень хорошо, если бы селекторы действительно работали, теоретически это хорошее и элегантное решение, но кажется, что оно сломано. ПОЦЕЛУЙ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...