Switch
控件是 Android 中用来表示开关状态的一个 UI 元素,它继承自 CompoundButton
,这意味着它也继承了 Button
的一些特性,比如事件处理等。Switch
控件主要用于二进制选择,即开和关两种状态。下面我将结合源码分析 Switch
的实现原理。
1. Switch 类定义
Switch
类定义如下:
1public class Switch extends CompoundButton {
2 // ...
3}
2. 构造函数
Switch
的构造函数如下:
1public Switch(Context context) {
2 this(context, null);
3}
4
5public Switch(Context context, AttributeSet attrs) {
6 this(context, attrs, android.R.attr.switchStyle);
7}
8
9public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
10 super(context, attrs, defStyleAttr);
11 initSwitch();
12}
构造函数中调用了 initSwitch
方法来初始化 Switch
的属性。
3. 初始化
初始化方法会设置默认属性,并读取自定义属性。
1void initSwitch() {
2 // ...
3 TypedArray a = getContext().obtainStyledAttributes(
4 mAttrs, R.styleable.Switch, mDefStyleAttr, 0);
5
6 // ...
7 // 读取样式属性
8 mThumbDrawable = a.getDrawable(R.styleable.Switch_thumb);
9 mTrackDrawable = a.getDrawable(R.styleable.Switch_track);
10 // ...
11
12 a.recycle();
13
14 // 初始化文本和图标
15 initCompoundButton();
16
17 // 设置默认的触摸反馈效果
18 setTouchFeedbackColorResource(android.R.color.holo_blue_bright);
19 // ...
20}
这里可以看到 Switch
通过 TypedArray
获取了自定义的样式属性,如 thumb
和 track
图标。
4. 状态变化
Switch
可以通过 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}
5. 状态集
Switch
使用状态集来管理不同的状态下的外观。
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}
6. 绘制
Switch
重写了 onDraw
方法来绘制文本和图标。
1@Override
2protected void onDraw(Canvas canvas) {
3 super.onDraw(canvas);
4 // ...
5 // 绘制 track 和 thumb
6 if (mTrackDrawable != null) {
7 mTrackDrawable.setBounds(mTrackRect);
8 mTrackDrawable.draw(canvas);
9 }
10
11 if (mThumbDrawable != null) {
12 mThumbDrawable.setBounds(mThumbRect);
13 mThumbDrawable.draw(canvas);
14 }
15 // ...
16}
7. 计算 thumb 和 track 的位置
Switch
需要计算 thumb 和 track 的位置以便正确地显示。
1void computeThumbPosition() {
2 final int trackWidth = mTrackRect.width();
3 final int thumbHalfWidth = mThumbRect.width() / 2;
4
5 if (trackWidth > 0 && thumbHalfWidth > 0) {
6 final int thumbPos = (trackWidth - thumbHalfWidth) * mThumbOffset + thumbHalfWidth;
7 mThumbRect.offset(mTrackRect.left + thumbPos, mTrackRect.top);
8 }
9}
8. 事件处理
Switch
通过处理点击事件来改变开关状态。
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. 焦点和触摸事件
Switch
通过处理焦点变化和触摸事件来更新其状态。
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. 适配器模式
Switch
通过 CompoundButton
实现了适配器模式,允许同时处理文本和图标。
1public abstract class CompoundButton extends Button implements CompoundButton.OnCheckedChangeListener {
2 // ...
3}
11. 事件监听器
Switch
支持通过 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. 样式和主题
Switch
支持通过 XML 属性来自定义样式。
1<Switch
2 android:id="@+id/switch"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"
5 android:textOn="On"
6 android:textOff="Off"
7 android:checked="true"
8 android:track="@drawable/switch_track"
9 android:thumb="@drawable/switch_thumb" />
总结
Switch
控件的核心在于两个主要的图形元素:track
(轨道)和 thumb
(滑块)。当状态改变时,thumb
的位置也会相应改变,从而模拟开关的效果。Switch
还提供了对触摸事件的支持以及事件监听器来响应状态的变化。