美文网首页
Android CheckBox setButtonDrawab

Android CheckBox setButtonDrawab

作者: teletian | 来源:发表于2017-07-19 21:33 被阅读104次

    当我们需要只显示 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 的。

    相关文章

      网友评论

          本文标题:Android CheckBox setButtonDrawab

          本文链接:https://www.haomeiwen.com/subject/sgdkkxtx.html