【问题标题】:Custom Checkable View which responds to Selector响应选择器的自定义可检查视图
【发布时间】:2012-07-02 12:08:11
【问题描述】:

我有一组FrameLayout,我希望它是可检查/可选择的,

也就是说,单击后我希望FrameLayout 显示为checked - 再次按下时我希望它变为unchecked。更重要的是,我希望通过使用<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_horizo​​ntal.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 代码)。

【问题讨论】:

    标签: android view custom-view


    【解决方案1】:

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

    【讨论】:

    • onCreateDrawableState 由于某种原因没有从 LinearLayout 调用。任何想法为什么?
    • 如果有人想获得完整的解决方案,请查看此存储库:github.com/shamanland/AndroidLayoutSelector 有自定义可点击/可检查 LinearLayout 就像 ToggleButton
    • 这不支持初始检查状态android:checked="true"
    【解决方案2】:

    这是 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;
        }
    }
    

    【讨论】:

    • 你应该添加performClick()方法,看看接受的答案
    【解决方案3】:

    尝试使用android:state_activated

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

    来自docs

    StateListDrawable 的状态值,当视图或其父视图具有 已“激活”意味着用户当前已将其标记为 兴趣。

    【讨论】:

    • 我应该把那个标签放在哪里?不适用于&lt;item&gt;
    • 它就像任何其他州一样。我在答案中添加了一个示例。
    • state_activated 完全没有区别(它也是 API 11)
    • 我认为我们错过了明显的...android:checkable="true"。在布局中尝试。再说一次,也许不是,我看到提到的唯一地方是用于构建菜单......虽然我想无论如何尝试它不会有什么坏处。
    • 嗯,在哪里?你有android:clickable,而不是android:checkable
    【解决方案4】:

    尝试在您的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"/>
    

    【讨论】:

    • 没有区别 - 我确保每个项目都是隐式的(同时包含 state_pressed 和 state_checked),以免混淆。
    【解决方案5】:

    除了上面格雷姆的回答 对toggle()做如下修改

    @Override
    public void toggle() {
        mChecked = !mChecked;
        refreshDrawableState();
    }
    

    【讨论】:

    • 我已将其包含在原始答案中
    • 这里唯一的补充是我们还需要在toggle()中调用refreshDrawableState()。
    【解决方案6】:

    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

    【讨论】:

    • 查看docs - “这是 state_checked 的另一种表示形式,用于将状态向下传播到视图层次结构。”,只有当您还想要您的孩子的孩子时,这样的声音才有用如果他们的父母被选中,查看回复true
    • Graeme 的解决方案适用于我的可检查按钮(我还按照 sujith 的建议将 refreshDrawableState() 添加到 setChecked() 和 toggle()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 2020-12-19
    相关资源
    最近更新 更多