Фон элемента ListView с помощью пользовательского селектора
Можно ли применить собственный фон к каждому элементу списка через селектор списка?
Селектор по умолчанию указывает @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 ответов
Я был разочарован этим сам и наконец решил это. Как намекнул Ромэн Гай, есть еще один штат, "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>
Решение от dglmtn не работает, если у вас есть 9-патч для рисования с отступом в качестве фона. Странные вещи случаются, я даже не хочу об этом говорить, если у вас есть такая проблема, вы их знаете.
Теперь, если вы хотите иметь вид списка с различными состояниями и 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"
/>
Это должно сделать вещь.
Никогда не используйте "цвет фона" для строк списка...
это заблокирует каждое действие селектора (была моя проблема!)
удачи!
Достаточно, если вы положите в 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>
Статья "Почему мой список черный? Оптимизация Android" в блоге разработчиков Android содержит подробное объяснение того, почему фон списка становится черным при прокрутке. Простой ответ: установите cacheColorHint в вашем списке на прозрачный (#00000000).
Вы можете написать тему:
<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 - это ваш пользовательский селектор. Извините, я не знаю, как написать свой код
Вместо:
android:drawable="@color/transparent"
записывать
android:drawable="@android:color/transparent"
Я всегда использую один и тот же метод, и он работает каждый раз, везде: я просто использую селектор вот так
<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" />
все показало работу без утомительных обходных путей. надеюсь, это поможет
Я не уверен, как добиться желаемого эффекта с помощью самого селектора - в конце концов, по определению, есть один селектор для всего списка.
Тем не менее, вы можете получить контроль над изменениями выбора и рисовать все, что вы хотите. В этом примере проекта я делаю селектор прозрачным и рисую полосу на выбранном элементе.
Команда FrostWire здесь.
Все API-интерфейсы селектора не работают должным образом. Попробовав все решения, представленные в этой теме, безрезультатно, мы просто решили проблему в момент раздувания элемента ListView.
Убедитесь, что ваш элемент сохраняет свое состояние, мы сделали это в качестве переменной-члена MenuItem (логическое значение выбрано)
Когда вы раздуваетесь, спросите, выбран ли базовый элемент, если так, просто установите нарисованный ресурс, который вы хотите использовать в качестве фона (будь то 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; }
Было бы очень хорошо, если бы селекторы действительно работали, теоретически это хорошее и элегантное решение, но кажется, что оно сломано. ПОЦЕЛУЙ.