响应选择器的自定义可检查视图
Posted
技术标签:
【中文标题】响应选择器的自定义可检查视图【英文标题】: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_
android:layout_
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
代码)。
【问题讨论】:
【参考方案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 的状态值,当视图或其父视图具有 已“激活”意味着用户当前已将其标记为 兴趣。
【讨论】:
我应该把那个标签放在哪里?不适用于<item>
。
它就像任何其他州一样。我在答案中添加了一个示例。
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()。以上是关于响应选择器的自定义可检查视图的主要内容,如果未能解决你的问题,请参考以下文章
我们可以用angular中的自定义css覆盖选择器的默认样式吗
如何为数组中的每个创建一个具有唯一图像和选择器的自定义 UIButton?