CheckBox 是 Android 中的一个常用控件,用于实现复选框的功能。它继承自 CompoundButton,后者又继承自 Button。CheckBox 可以用来表示一个布尔值的选择状态,通常用于收集用户的选择,例如在表单中选择多个选项。
接下来,我们将结合源码来分析 CheckBox 的实现原理。
1. CheckBox 类定义
CheckBox 类定义如下:
1public class CheckBox extends CompoundButton {
2    // ...
3}CheckBox 继承自 CompoundButton,因此它具备 CompoundButton 的所有功能,并且可以显示文本和图标。
2. 构造函数
CheckBox 的构造函数如下:
1public CheckBox(Context context) {
2    this(context, null);
3}
4
5public CheckBox(Context context, AttributeSet attrs) {
6    this(context, attrs, android.R.attr.checkboxStyle);
7}
8
9public CheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
10    super(context, attrs, defStyleAttr);
11    init(context, attrs, defStyleAttr, 0);
12}构造函数中调用了 init 方法来初始化 CheckBox 的属性。
3. 初始化
初始化方法会设置默认属性,并读取自定义属性。
1private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
2    // ...
3    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckBox, defStyleAttr, defStyleRes);
4    // ...
5    // 读取样式属性
6    mButtonDrawable = a.getDrawable(R.styleable.CheckBox_button);
7    // ...
8    a.recycle();
9    // 初始化文本和图标
10    initCompoundButton();
11}4. 设置按钮图标
CheckBox 通常会显示一个图标来表示选中状态。
1@Override
2public void setButtonDrawable(Drawable buttonDrawable) {
3    super.setButtonDrawable(buttonDrawable);
4    // ...
5}5. 状态变化
CheckBox 可以通过 setChecked 方法来改变选中状态。
1public void setChecked(boolean checked) {
2    if (checked != mChecked) {
3        mChecked = checked;
4        refreshDrawableState();
5        if (!mPressed) {
6            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
7        }
8        performClick();
9    }
10}6. 状态集
CheckBox 使用状态集来管理不同的状态下的外观。
1@Override
2protected int[] onCreateDrawableState(int extraSpace) {
3    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
4    if (isChecked()) {
5        mergeDrawableStates(drawableState, CHECKED_STATE_SET);
6    }
7    if (isPressed()) {
8        mergeDrawableStates(drawableState, PRESSED_STATE_SET);
9    }
10    return drawableState;
11}7. 绘制
CheckBox 重写了 onDraw 方法来绘制文本和图标。
1@Override
2protected void onDraw(Canvas canvas) {
3    super.onDraw(canvas);
4    // ...
5    // 绘制文本和图标
6    if (mButtonDrawable != null) {
7        mButtonDrawable.setBounds(mButtonRect);
8        mButtonDrawable.draw(canvas);
9    }
10    // ...
11}8. 事件处理
CheckBox 通过处理点击事件来改变选中状态。
1@Override
2public boolean performClick() {
3    toggle();
4    playSoundEffect(SoundEffectConstants.CLICK);
5    return super.performClick();
6}
7
8public void toggle() {
9    setChecked(!mChecked);
10}9. 焦点和触摸事件
CheckBox 通过处理焦点变化和触摸事件来更新其状态。
1@Override
2public boolean onHoverEvent(MotionEvent event) {
3    // ...
4    return super.onHoverEvent(event);
5}
6
7@Override
8public boolean onTouchEvent(MotionEvent event) {
9    // ...
10    return super.onTouchEvent(event);
11}10. 适配器模式
CheckBox 通过 CompoundButton 实现了适配器模式,允许同时处理文本和图标。
1public abstract class CompoundButton extends Button implements CompoundButton.OnCheckedChangeListener {
2    // ...
3}11. 事件监听器
CheckBox 支持通过 OnCheckedChangeListener 监听选中状态的变化。
1public static abstract class OnCheckedChangeListener implements BaseAdapter.DataSetObserver {
2    // ...
3}
4
5public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
6    mOnCheckedChangeListener = listener;
7}
8
9@Override
10public void performClick() {
11    // ...
12    if (mOnCheckedChangeListener != null) {
13        mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
14    }
15    // ...
16}12. 样式和主题
CheckBox 支持通过 XML 属性来自定义样式。
1<CheckBox
2    android:id="@+id/check_box"
3    android:layout_width="wrap_content"
4    android:layout_height="wrap_content"
5    android:text="Option 1"
6    android:checked="false"
7    android:button="@drawable/check_box_selector" />总结
CheckBox 的实现基于 CompoundButton,它继承自 Button。CheckBox 主要通过设置按钮图标和监听选中状态的变化来实现其功能。它还支持通过自定义属性来自定义样式,并且可以通过事件监听器来响应状态的变化。