Лучшее решение с поддержкой всех уровней API - реализовать функцию Checkable для элемента списка View
, что означает, что вид сверху вашего макета элемента списка должен реализовывать интерфейс Checkable
(в моем случае это был TextView, но то же самое можно применить к ViewGroup
классам, таким как LinearLayout
). Когда вы нажимаете на элемент списка, метод ListView
вызывает 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>