Ответ 1
Ответ заключается в использовании состояния android:state_activated="true"
вместо состояния "выбрано". Подробнее об этом здесь: ListFragment Item Selected Background
Итак, у меня есть ListView, и я хочу изменить цвет каждого элемента фона и текста. Этот ListView находится внутри ListFragment. Мой код раздувает макет в onCreateView
и раздувает макет каждого элемента в newView
.
android:state_pressed="true"
работает нормально, всякий раз, когда я нажимаю один элемент, фон меняется на этот цвет. Но при выборе элемента ни цвет, ни цвет текста не изменяется, хотя я определил элемент с android:state_selected="true"
в селекторе.
Изменить: я использую SDK уровня 11 (Android 3.0) и Motorola Xoom.
Макет фрагмента списка:
<?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="fill_parent"
android:orientation="vertical">
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
Макет элемента списка:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="25dp"
android:background="@drawable/list_item_bg_selector">
<TextView android:id="@+id/form_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_xlarge"
android:textStyle="bold"
android:textColor="@drawable/list_item_text_selector" />
<TextView android:id="@+id/form_subtitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_medium"
android:textStyle="normal"
android:layout_marginTop="5dp"
android:textColor="@drawable/list_item_text_selector" />
</LinearLayout>
Фоновый переключатель:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@color/white" />
<item
android:state_selected="true"
android:drawable="@drawable/list_item_bg_selected" />
<item
android:drawable="@color/list_bg" />
</selector>
Селектор текста:
<?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/white" />
<item
android:drawable="@color/list_text_blue" />
</selector>
Ответ заключается в использовании состояния android:state_activated="true"
вместо состояния "выбрано". Подробнее об этом здесь: ListFragment Item Selected Background
Лучшим решением с поддержкой всех уровней API является реализация функции Checkable для элемента списка View
, что означает, что верхний вид макета элемента списка должен реализовывать интерфейс Checkable
(в моем случае это был TextView, но то же самое можно применить к классам ViewGroup
, таким как LinearLayout
). Когда вы нажимаете на элемент списка, метод ListView
call setChecked
и там мы меняем состояние представления, чтобы использовать селектор android:state_checked="true"
. Вместе со списком android:choiceMode="singleChoice"
он выберет только один элемент.
Трюк состоит в том, чтобы переопределить метод onCreateDrawableState
и установить здесь проверочное состояние для чертежей. См. Пример SelectableTextView
ниже. После вызова setChecked
проверенное состояние сохраняется и называется refreshDrawableState
.
Пример SelectableTextView
:
package com.example.widget.SelectableTextView;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.TextView;
public class SelectableTextView extends TextView implements Checkable {
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
private boolean mChecked;
public SelectableTextView(Context context) {
super(context);
}
public SelectableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void toggle() {
setSelected(!mChecked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
Пример макета selectable_list_item.xml
:
<?xml version="1.0" encoding="utf-8"?>
<com.example.widget.SelectableTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="@color/list_item_selector_foreground"
android:background="@drawable/list_item_selector_background"
tools:text="Item 1"/>
Пример list_item_selector_foreground.xml
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- checked -->
<item android:color="@color/list_item_text_active" android:state_checked="true"/>
<item android:color="@color/list_item_text"/>
</selector>
Пример list_item_selector_background.xml
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/list_item_background_selected" android:state_pressed="true"/>
<item android:drawable="@color/list_item_background_selected" android:state_focused="true"/>
<item android:drawable="@color/list_item_background_active" android:state_checked="true"/>
<item android:drawable="@color/list_item_background"/>
</selector>
Не забудьте установить clickable="true"
для макета. Это решило мою проблему.
Макет списка:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_item_bg_selector"
android:clickable="true" >
<TextView
android:id="@+id/tvNewsPreviewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3"
android:ellipsize="end"
android:textSize="@dimen/news_preview_title_textsize"
android:textStyle="bold" />
</RelativeLayout>
Фоновый переключатель:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/black" />
<gradient android:startColor="@color/white" android:endColor="@color/white" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/holo_gray_darker" />
<gradient android:startColor="@color/holo_gray_bright" android:endColor="@color/holo_gray_bright" />
</shape>
</item>
</selector>
@Andrew S: Наряду с использованием активированного состояния в селекторе, активированное состояние должно быть установлено на false для случая по умолчанию, как показано ниже в селекторном коде.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
android:state_activated="false"
android:color="@color/dark_text_blue"/>
<item android:state_pressed="true"
android:color="@color/red"/>
<item android:state_activated="true"
android:color="@color/red"/>
</selector>