响应选择器的自定义可检查视图



我有一组FrameLayout,我想检查/可选,

也就是说,单击后,我希望FrameLayout显示为checked - 再次按下时,我希望它变成 un 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_horizontal.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代码被调用)。

将以下代码添加到 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;
    }
}

尝试使用 android:state_activated .

<item android:drawable="@color/HighlightColor"      android:state_activated="true"/> 

从文档中:

StateListDrawable 的状态值,当视图或其父视图具有 已"激活",表示用户当前已将其标记为 利息。

尝试对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"/>

除了上面格雷姆的回答对 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>

并在setChecked内使用setActivated

@Override
public void setChecked(boolean checked) {
    mChecked = checked;
    setActivated(checked);
}

仅此而已。此处不需要实现onCreateDrawableState

最新更新