當(dāng)我們需要只顯示 CheckBox 的文字抖拴,而不顯示按鈕的時(shí)候凡恍,通常在 XML 文件中設(shè)置 CheckBox 的 android:button="@null"。
當(dāng)我們自定義 CheckBox 并希望在代碼中控制按鈕不顯示的時(shí)候,可以 setButtonDrawable(null) 來(lái)達(dá)到效果狈癞。
但是有一個(gè)問(wèn)題履羞,setButtonDrawable(null) 在 4.x 中是沒(méi)有效果的峦萎,從 5.0 開始才有效果。
為了調(diào)查為什么 4.x 沒(méi)有效果忆首,我們來(lái)分別看看 4.4 和 5.0 的源碼爱榔,到底 setButtonDrawable 方法有什么不同。
關(guān)于查看 Android 各版本的源碼推薦兩個(gè)網(wǎng)站:
GrepCode
AndroidXRef
先來(lái)看 4.4 的源碼糙及,其實(shí) 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,就直接跳過(guò)去了,沒(méi)有任何效果唇聘!
再來(lái)看看 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 默認(rèn)是有按鈕的迟郎,所以默認(rèn) mButtonDrawable 是不為 null 的剥险,所以判斷成立,mButtonDrawable 被賦為 null宪肖。
也許你會(huì)問(wèn)表制,為什么 android:button="@null" 不管是 4.x 還是 5.0 之后都是有效果的呢?那我們就得看看構(gòu)造方法初始化的源碼了
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);
}
......
......
}
可以看到匈庭,如果傳進(jìn)來(lái)的 Drawable 不為 null夫凸,才設(shè)置初始按鈕。這部分代碼 4.x 和 5.0 以后都一樣阱持,所以 android:button="@null" 是不受版本影響的夭拌。
至于初始按鈕的樣式可以看 CheckBox 中的構(gòu)造方法的源碼
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>
繼續(xù)看 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>
繼續(xù)到 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 默認(rèn)的按鈕效果。
等等镶骗,說(shuō)了這么多桶现,到底 setButtonDrawable(null) 在 4.x 版本中無(wú)效的問(wèn)題怎么解決呢?辦法很簡(jiǎn)單鼎姊,setButtonDrawable(new StateListDrawable()) 即可骡和!
最后,不僅僅 CheckBox相寇,所有繼承自 CompoundButton 的控件都有這個(gè)問(wèn)題慰于,可以看看 CompoundButton 有哪些子控件
如圖,RadioButton唤衫,Switch 等等的控件都是繼承自 CompoundButton 的婆赠。