热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidCheckBoxsetButtonDrawable(null)在4.x版本中无效

当我们需要只显示CheckBox的文字,而不显示按钮的时候,通常在XML文件中设置CheckBox的android:button”@null”。当我们自定义Check

当我们需要只显示 CheckBox 的文字,而不显示按钮的时候,通常在 XML 文件中设置 CheckBox 的 android:button=”@null”。

当我们自定义 CheckBox 并希望在代码中控制按钮不显示的时候,可以 setButtonDrawable(null) 来达到效果。

但是有一个问题,setButtonDrawable(null) 在 4.x 中是没有效果的,从 5.0 开始才有效果。

为了调查为什么 4.x 没有效果,我们来分别看看 4.4 和 5.0 的源码,到底 setButtonDrawable 方法有什么不同。

关于查看 Android 各版本的源码推荐两个网站:
GrepCode
AndroidXRef

先来看 4.4 的源码,其实 setButtonDrawable 方法在 CheckBox 的父类 CompoundButton 中。

   /**
* Set the background to a given Drawable
*
* @param d The Drawable to use as the background
*/

public void setButtonDrawable(Drawable d) {
if (d != null) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}
d.setCallback(this);
d.setVisible(getVisibility() == VISIBLE, false);
mButtOnDrawable= d;
setMinHeight(mButtonDrawable.getIntrinsicHeight());
}

refreshDrawableState();
}

可以看到如果 Drawable 为 null,就直接跳过去了,没有任何效果!

再来看看 5.0 中的源码

    public void More ...setButtonDrawable(Drawable d) {
if (mButtonDrawable != d) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}

mButtOnDrawable= d;

if (d != null) {
d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
d.setVisible(getVisibility() == VISIBLE, false);
setMinHeight(d.getIntrinsicHeight());
applyButtonTint();
}
}
}

可以看到并不是判断为不为 null,而是判断和之前的一样不一样,CheckBox 默认是有按钮的,所以默认 mButtonDrawable 是不为 null 的,所以判断成立,mButtonDrawable 被赋为 null。

也许你会问,为什么 android:button=”@null” 不管是 4.x 还是 5.0 之后都是有效果的呢?那我们就得看看构造方法初始化的源码了

     public More ...CompoundButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);

final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);

final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
setButtonDrawable(d);
}
......
......
}

可以看到,如果传进来的 Drawable 不为 null,才设置初始按钮。这部分代码 4.x 和 5.0 以后都一样,所以 android:button=”@null” 是不受版本影响的。

至于初始按钮的样式可以看 CheckBox 中的构造方法的源码

public CheckBox(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.checkboxStyle);
}

可以看到初始样式是 com.android.internal.R.attr.checkboxStyle。
com.android.internal….可以到 android / frameworks / base / core / res / res / values 下面去找。
checkboxStyle 在 themes.xml 中

<item name="checkboxStyle">@style/Widget.CompoundButton.CheckBoxitem>

继续看 style.xml 中的 Widget.CompoundButton.CheckBox

    <style name="Widget.CompoundButton.CheckBox">
<item name="button">?attr/listChoiceIndicatorMultipleitem
>
style>

listChoiceIndicatorMultiple 还是在 themes.xml 中

<item name="listChoiceIndicatorMultiple">@drawable/btn_checkitem>

继续到 android / frameworks / base / core / res / res / drawable 下去找 btn_check.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">



<item android:state_checked="true" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on" />

<item android:state_checked="false" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off" />


<item android:state_checked="true" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_pressed" />

<item android:state_checked="false" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_pressed" />


<item android:state_checked="true" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_selected" />

<item android:state_checked="false" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_selected" />


<item android:state_checked="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off" />

<item android:state_checked="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on" />





<item android:state_checked="true" android:state_window_focused="false"
android:drawable="@drawable/btn_check_on_disable" />

<item android:state_checked="false" android:state_window_focused="false"
android:drawable="@drawable/btn_check_off_disable" />


<item android:state_checked="true" android:state_focused="true"
android:drawable="@drawable/btn_check_on_disable_focused" />

<item android:state_checked="false" android:state_focused="true"
android:drawable="@drawable/btn_check_off_disable_focused" />


<item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable" />
<item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable" />

selector>

到这边,我们就找到了 CheckBox 默认的按钮效果。

等等,说了这么多,到底 setButtonDrawable(null) 在 4.x 版本中无效的问题怎么解决呢?办法很简单,setButtonDrawable(new StateListDrawable()) 即可!

最后,不仅仅 CheckBox,所有继承自 CompoundButton 的控件都有这个问题,可以看看 CompoundButton 有哪些子控件

如图,RadioButton,Switch 等等的控件都是继承自 CompoundButton 的。


推荐阅读
author-avatar
zy一生的最爱_149
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有