Пользовательский проверяемый вид, который отвечает на селектор
У меня есть группа FrameLayout
который я хочу чтобы можно было проверить / выбрать,
То есть после клика мне бы хотелось FrameLayout
отображать как checked
- при повторном нажатии я бы хотел, чтобыchecked
, Более того, я хочу, чтобы эта визуальная очередь была описана как обычно через использование <selector>
,
Я не могу заставить это работать - я не уверен, что мне не хватает:
public class CheckableFrameLayout extends FrameLayout implements Checkable {
private boolean mChecked = false;
public CheckableFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setChecked(boolean checked) {
mChecked = checked;
refreshDrawableState();
}
public boolean isChecked() {
return mChecked;
}
public void toggle() {
setChecked(!mChecked);
}
}
Макет CheckableFrameLayout
:
<com.test.view.CheckableFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/selector_horizontal"
android:clickable="true" >
Селектор, поддерживающий его (selector_horizont.xml):
<item android:drawable="@drawable/selector_vertical_selected" android:state_pressed="false" android:state_checked="true"/>
<item android:drawable="@drawable/selector_vertical_pressed" android:state_pressed="true" android:state_checked="false"/>
<item android:drawable="@drawable/selector_vertical_normal" android:state_pressed="false" android:state_checked="false"/>
Используя приведенный выше код, "state_pressed" работает нормально, но само представление не проверяется (это не Checkable
код, вызываемый как обнаруженный с помощью отладки).
6 ответов
Добавление следующего кода в Checkable
Класс позволяет селекторам работать:
private static final int[] CheckedStateSet = {
android.R.attr.state_checked,
};
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CheckedStateSet);
}
return drawableState;
}
@Override
public boolean performClick() {
toggle();
return super.performClick();
}
Вот полный рабочий пример для CheckableButton. Это также работает на Android 4.2.
public class CheckableButton extends Button implements Checkable {
private static final int[] CheckedStateSet = { android.R.attr.state_checked };
private boolean mChecked = false;
public CheckableButton(Context context) {
super(context);
}
public CheckableButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CheckableButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void setChecked(boolean checked) {
mChecked = checked;
refreshDrawableState();
}
@Override
public void toggle() {
mChecked = !mChecked;
refreshDrawableState();
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CheckedStateSet);
}
return drawableState;
}
}
В дополнение к ответу Грэма, приведенному выше, сделайте следующую модификацию toggle()
@Override
public void toggle() {
mChecked = !mChecked;
refreshDrawableState();
}
Решение от Graeme не сработало от меня под Android 4.0.3 (и я полагаю, что оно не будет работать под 4.0 тоже). Вместо этого вы можете изменить state_checked
в state_activated
:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/activated_image" android:state_pressed="false" android:state_activated="true" />
<item android:drawable="@drawable/not_activated_image" android:state_pressed="false" android:state_activated="false"/>
</selector>
и использовать setActivated
внутри вашего setChecked
:
@Override
public void setChecked(boolean checked) {
mChecked = checked;
setActivated(checked);
}
и это все. Внедрение onCreateDrawableState
здесь не требуется
Попробуйте изменить порядок тегов в вашем selector_horizontal.xml
Они оцениваются сверху вниз. Похоже, что в вашем случае либо android:state_pressed="false" or android:state_pressed="true"
применяется, и оценка никогда не достигает третьей строки с android:state_checked="true"
Попробуйте переместить первую строку в последнюю:
<item android:drawable="@color/HighlightColor" android:state_pressed="true"/>
<item android:drawable="@color/selected_color" android:state_checked="true"/>
<item android:drawable="@android:color/transparent" android:state_pressed="false"/>
Попробуйте использовать android:state_activated
,
<item android:drawable="@color/HighlightColor" android:state_activated="true"/>
Из документов:
Значение состояния для StateListDrawable, устанавливается, когда представление или его родительский элемент были "активированы", что означает, что пользователь в настоящее время пометил его как представляющий интерес.