Фон элемента ListView с помощью пользовательского селектора

100

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

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

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

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

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

Заранее благодарим за помощь!

Теги:
listview

10 ответов

127
Лучший ответ

Я был разочарован этим сам и, наконец, решил его. Как намекнул Ромен Гай, есть другое государство, "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>
  • 1
    Спасибо за подробный ответ. Как я уже упоминал в своем вопросе, это именно то, что я делаю в данный момент, и это работает довольно хорошо.
  • 0
    К сожалению, мне все еще не удается настроить вид списка. Я опубликовал свои конкретные проблемы здесь: stackoverflow.com/questions/5426385/… ; Буду признателен за любой вклад, который вы можете иметь.
Показать ещё 5 комментариев
78

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

Теперь, если вы хотите иметь listview с разными состояниями и 9-патч-образами (он будет работать с любыми чертежами и цветами, я думаю), вам нужно сделать 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-патчей, я уверен, что это может быть полезно в моих будущих реализациях. Это должен быть лучший ответ, потому что этот метод более чистый и ремонтопригодный.
  • 27
    Извините, но это такие вещи, которые иногда заставляют задуматься, почему эти чертовы API-интерфейсы должны быть такими дерьмовыми. Android еще многое предстоит пройти. Такие базовые вещи не должны быть такими PITA.
Показать ещё 10 комментариев
17

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

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

Удачи!

  • 3
    Это неправда. Просто используйте селектор в качестве фона, а не статического цвета или рисования
  • 0
    это должно было означать «цвет фона». полностью принять ваши слова.
Показать ещё 1 комментарий
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
    офигенно ... простейший пример
  • 1
    А также сделать селектор списка прозрачным
Показать ещё 1 комментарий
5

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

  • 1
    Примерная простота, но она работает очень хорошо. Спасибо за Romain Guy ... <ListView ... android: cacheColorHint = "# 00000000"> </ ListView> Это все!
  • 0
    Не благодари Ромен Гая. Он часть проблемы. В такой ОС не должно быть так много «скрытых трюков» или других хаков. Несмотря на то, что я люблю Android, это огромная куча собачьего мусора по сравнению с другими SDK (даже более новыми / менее зрелыми!).
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 - это ваш пользовательский селектор Мне жаль, что я не знаю, как написать свой код

  • 0
    Спасибо за помощь, но это не помогает напрямую установить заданный по умолчанию фон списка с помощью селектора.
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" />

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

2

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

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

  • 0
    Действительно, имеет смысл иметь только один селектор. Я думаю, что я (или был) немного смущен существованием предложения <item android:state_focused="false" android:drawable="@android:color/transparent& /> в селекторе по умолчанию.
  • 0
    Марк, играя (с той же проблемой, что и Джил), я попробовал ваше решение, оно только частичное только для трекбола, Ничего не выбрано вызывается, когда вы касаетесь элементов, используя только касание, и вызывается onItemClicked, если вы хотите что-то подобное, скорее всего Вы должны отслеживать выбранные и нажатые позиции внутри ListView и рисовать то, что вам нужно, в самом Item (сделайте его настраиваемым View) и в dispatchDraw ListView.
Показать ещё 1 комментарий
-3

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

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

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

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

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

  • 1
    Селекторы работают. Вы просто не понимаете, как их использовать ..
  • 0
    Я хочу попробовать это решение, не могли бы вы дать более подробное объяснение или полное решение? Спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню