android:state_checked仅对实现checkable接口的控件(如checkbox、radiobutton、switch或自定义实现类)生效;需调用setchecked()触发状态更新,且selector中须正确定义state_checked与其他状态的组合及兜底项。

selector 里 android:state_checked 不生效?先看控件是否支持
很多同学加了 android:state_checked="true" 却没反应,根本原因是:不是所有 View 都支持这个状态。它只对实现了 Checkable 接口的控件有效,比如 CheckBox、RadioButton、Switch,或者你手动继承并实现的自定义控件。
常见错误现象:TextView 或普通 LinearLayout 套了个 selector,点了没变化——它们默认不维护 checked 状态,系统压根不会去匹配 android:state_checked。
- 确认控件类名是否属于
CheckBox/RadioButton/Switch - 如果是自定义 View,必须重写
setChecked()、isChecked()和toggle(),并调用refreshDrawableState() - 别在
Button上硬套state_checked,它不实现Checkable,xml 会静默忽略该属性
XML selector 中 android:state_checked 的匹配逻辑
这个状态只在控件当前 isChecked() == true 时触发,和点击事件、选中动画无关,纯属状态快照匹配。顺序很重要:系统从上到下遍历 <item></item>,取第一个全部条件都满足的项。
容易踩的坑是把 state_checked 和 state_pressed 混在一起写,结果按住时不显示按下效果(因为 state_checked 优先级更高,且为 true 时仍满足“未按压”条件)。
- 需要同时响应“选中+按下”,得显式写成:
android:state_checked="true" android:state_pressed="true" - 想让“未选中时的按下态”也生效,必须单独写一项:
android:state_checked="false" android:state_pressed="true" - 别漏掉兜底项(无任何 state 属性的
<item></item>),否则未匹配时可能显示透明或默认色
Java/kotlin 代码里动态控制 setChecked() 才能触发状态更新
光改 XML 或后台变量没用,必须调用控件的 setChecked(true),系统才会刷新 drawable 状态、触发 selector 重匹配。
常见错误:用 setSelected(true) 或直接改布尔字段,这不会触发 state_checked 变化。
-
checkBox.setChecked(true)是唯一可靠方式(RadioButton同理) - 在
RecyclerView里复用 item 时,每次onBindViewHolder都要显式调用setChecked(),不能只靠初始 XML - 如果用
CompoundButton.OnCheckedChangeListener,回调里的isChecked参数才是真实状态,别依赖 view 自身字段
Android 5.0+ 的 ripple 和 state_checked 共存问题
用 <ripple></ripple> 当根节点时,内部 <item></item> 的 state_checked 依然有效,但要注意层级覆盖关系:ripple 的波纹层默认在 foreground,而 selector 通常设在 background,两者不冲突;但如果 selector 本身是 ripple,就得确保子 <item></item> 正确嵌套。
性能提示:过度嵌套 <ripple> + <selector> + <layer-list></layer-list></selector></ripple> 容易导致绘制变慢,尤其在列表快速滚动时。
- 推荐方案:background 用普通 selector 控制颜色/形状,foreground 单独设
android:foreground="?attr/selectableItemBackgroundBorderless" - 避免在
<ripple></ripple>内再套完整 selector,改用android:state_*直接控制<item></item>的drawable - 测试真机 Android 6.0 以下机型,部分旧版本对
state_checked在 ripple 中的支持不一致
事情说清了就结束。真正卡住人的,往往不是语法写错,而是控件没实现 Checkable,或者忘了调 setChecked() 这一步。