Android按钮背景ColorStateList不生效问题排查与解决
最近给Android按钮配置背景颜色状态列表时踩了个大坑——不管怎么调整配置,按钮始终显示Material主题里colorPrimary对应的白色,试了好几种方案都没效果,最后终于找到了解决办法,分享给同样遇到这个问题的开发者:
问题场景
我参考相关方案试图为按钮配置不同状态(启用、禁用、按压等)的背景色,但无论状态怎么切换,按钮始终是白色,完全不按定义的ColorStateList渲染。
我尝试过的无效方案
方案1:Drawable类型StateList配置
先在res/drawable下编写状态选择器:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:drawable="@color/KeyActionPrimary"/> <!-- enabled --> <item android:state_enabled="false" android:drawable="@color/KeyActionButtonDeactivated"/> <!-- disabled --> <item android:state_pressed="true" android:drawable="@color/KeyActionPrimary"/> <!-- pressed --> <item android:state_focused="true" android:drawable="@color/KeyActionPrimary"/> <!-- focused --> <item android:drawable="@color/KeyActionPrimary"/> <!-- default --> </selector>
然后在Button布局中设置android:background="@drawable/state_controlled_key_action_button",结果完全没效果,按钮依旧是白色。
方案2:Shape+ColorStateList组合尝试
接着试了Shape搭配ColorStateList的方式:
先编写Shape配置(res/drawable目录):
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/primary_button_color" /> <stroke android:width="@dimen/btn_stroke" android:color="@color/primary_button_stroke_color"/> <corners android:radius="@dimen/btn_radius"/> </shape>
再在res/color下编写ColorStateList:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:color="@color/Primary"/> <!-- pressed --> <item android:state_enabled="false" android:color="@color/PrimaryButtonDeactivated"/> <!-- pressed --> <item android:state_pressed="true" android:color="@color/Primary"/> <!-- pressed --> <item android:state_focused="true" android:color="@color/Primary"/> <!-- focused --> <item android:color="@color/Primary"/> <!-- default --> </selector>
将Shape设为按钮的background后,问题依旧,按钮还是白色。
我原本以为显式指定background会覆盖主题样式,但显然Material主题的Button有特殊的样式优先级处理。
最终解决办法:用backgroundTint配合ColorStateList
和朋友讨论后发现,Material Button需要通过backgroundTint属性来设置背景颜色状态,而非直接设置background。
步骤1:在res/color下定义ColorStateList
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:color="@color/KeyActionColorOnPrimary"/> <item android:state_enabled="true" android:color="@color/KeyActionPrimary"/> <item android:state_enabled="false" android:color="@color/lime"/> <item android:state_focused="true" android:color="@color/KeyActionPrimary"/> <item android:color="@color/KeyActionPrimary"/> </selector>
步骤2:在Button布局中设置backgroundTint
<Button android:id="@+id/buttonSTART" android:layout_width="@dimen/btn_width" android:layout_height="@dimen/btn_height" android:layout_marginStart="4dp" android:layout_marginEnd="4dp" android:layout_marginBottom="16dp" android:backgroundTint="@color/key_action_button_color" android:padding="@dimen/btn_padding" android:text="@string/btn_start" android:textColor="@color/key_action_button_text_color" app:autoSizeTextType="uniform" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/btnSCORES" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" />
这样设置后,按钮的不同状态终于能正确显示对应颜色了!而且不需要额外修改主题样式,完美保留Material Design风格,只需要给需要特殊样式的按钮单独设置backgroundTint和textColor即可。
内容的提问来源于stack exchange,提问作者UnknownError

