Android CheckBox setButtonDrawable(null) 在 4.x 版本中无效

当我们需要只显示 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.CheckBox</item>

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

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

listChoiceIndicatorMultiple 还是在 themes.xml 中

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

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

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Enabled states -->

    <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" />


    <!-- Disabled states -->

    <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 的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值