Switch实现原理分析

news2024/9/8 23:57:10

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 获取了自定义的样式属性,如 thumbtrack 图标。

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 还提供了对触摸事件的支持以及事件监听器来响应状态的变化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1958020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务--配置管理

现在依然还有几个问题需要解决&#xff1a; 网关路由在配置文件中写死了&#xff0c;如果变更必须重启微服务 某些业务配置在配置文件中写死了&#xff0c;每次修改都要重启服务 每个微服务都有很多重复的配置&#xff0c;维护成本高 这些问题都可以通过统一的配置管理器服…

DRAM组件级故障预测模型,如何提升系统可靠性?-2

一、DRAM原理与可靠性 在深入探讨DRAM系统的可靠性问题前&#xff0c;我们需要明确几个基本概念。首先&#xff0c;故障指的是可能导致系统错误的物理缺陷&#xff0c;而错误则是系统实际状态与期望状态之间的差异。故障可分为暂时性故障和永久性故障&#xff1a;前者由外部因…

谁说PDF编辑器都一样?这5款让你大开眼界!

如今&#xff0c;PDF文档已经成了咱们工作生活中必不可少的东西。无论是看学术报告、合同协议&#xff0c;还是日常阅读的电子书&#xff0c;都能在不同的设备上保持一致的格式&#xff0c;成了大家最爱用的文档格式之一。但是&#xff0c;面对这么多PDF编辑器&#xff0c;你是…

当我在星巴克连上家里的服务器,光猫桥接打通IPv6,你是值得的

我们的课程环境是构建在一个256GB内存&#xff0c;192核CPU的集群上&#xff0c;学员可以通过浏览器&#xff0c;输入地址访问。要在阿某云上租这样一个服务器&#xff0c;价格并不便宜。所以&#xff0c;这些服务器一直放在公司里&#xff0c;创业期间&#xff0c;公司也就是租…

Docker三大基础组件

Docker有三个重要的概念&#xff1a;仓库、镜像和容器 &#xff0c;它们是Docker的三大基础组件&#xff0c;这三个组件共同构成了Docker的核心架构&#xff0c;使得Docker能够实现对应用程序的便捷打包、分发和运行。 Docker使用客户端-服务器体系结构。Docker客户端与Docker守…

angular入门基础教程(十一)与服务端数据交互

前后端分离开发&#xff0c;少不了与后端进行数据接口的对接&#xff0c;在vue&#xff0c;react中我们要借助第三方的axios来进行数据请求。在ng中&#xff0c;为我们封装了了一层httpClient&#xff0c;我们直接使用即可 依赖注入 我们需要再次封装一次 import { HttpClie…

虚假的互联网信息?不妨从IT的角度理解【景观社会】

博主前言&#xff1a;“我思故我在”&#xff0c;笛卡尔的这一哲学命题&#xff0c;大抵上次还比较熟络的时光还是高中亦或复习考研政治的岁月里。这是一个光怪陆离的社会——或者说网络社会&#xff0c;形形色色的消息充斥在脑海之时&#xff0c;你是否还能认识真正的自己&…

3.2.微调

微调 ​ 对于一些样本数量有限的数据集&#xff0c;如果使用较大的模型&#xff0c;可能很快过拟合&#xff0c;较小的模型可能效果不好。这个问题的一个解决方案是收集更多数据&#xff0c;但其实在很多情况下这是很难做到的。 ​ 另一种方法就是迁移学习(transfer learning…

window长时间不关机,卡顿处理方法

window使用一短时间非常卡&#xff0c;快速处理办法如下&#xff1a; 1、windowR 输入%temp% 手动删除临时目录文件。 2、windowR输入cleanmgr 磁盘清理 3、恶意软件删除工具 删除流行恶意软件。

What Is RPC(Remote Procedure Call,远程过程调用)

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种计算机通信协议&#xff0c;它允许一个计算机程序通过网络调用另一个计算机程序中的子程序&#xff08;也就是远程过程&#xff09;&#xff0c;并获取返回值。RPC服务是分布式计算的重要基础&…

面向对象程序设计(C++)模版初阶

1. 函数模版 1.1 函数模版概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实参类型产生函数的特定类型版本&#xff0c;可以类比函数参数&#xff0c;函数模版就是将函数参数替换为特定类型版本 1.2 函数模版格…

mlp与attention的计算时间复杂度分别为多少?PAtchtst为啥patch后为啥attention计算量降低?

感谢分享 看这篇博客的时候&#xff0c;因为patch后做了一个fc的映射&#xff0c;也是有计算的消耗嘛&#xff0c;好奇为什么说patchtst能够减小“注意力图的内存使用和计算复杂度减少了S倍&#xff0c;从而在计算资源有限的情况下允许模型查看更长的历史序列。“ 所以思考了一…

【时时三省】(C语言基础)循环语句while(2)

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 getchar和scanf的作用 示例: int main ( ) &#xff5b; char password[20] ( 0 ) ; printf ( "请输入密码&#xff1a;> " )&#xff1b; scanf ( " &#xff05;s…

Redis:未授权访问

Redis Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的高性能键值对&#xff08;key-value&#xff09;数据库&#xff0c;支持多种类型的数据结构。 核心特性 内存存储&#xff1a;Redis将所有数据存储在内存中&#xff0c;能够提供极高的读写性能。 …

jumpserver web资源--远程应用发布机

1、环境 jumpserver:3.10.10 远程发布机&#xff1a;windows 2019 2、windows 2019准备 保证windows 正常登录&#xff0c;并且可以访问jumpserver 3、添加远程发布机 能正常连接就继续 可看到这里正常了 4、添加web资源 找到我们需要自动登录界面 获取相关元素选…

独立3D网络游戏《战域重甲》开发与上架经验分享

“ 小编阿麟&#xff1a;心之所向便是光&#xff0c;我们都是追光者!这位独立游戏开发者的产品能力已经不输给许多小团队&#xff0c;希望他的故事和经验分享&#xff0c;可以给走在同样道路上的朋友一些信心和帮助。 背景介绍 2023年年底的时候&#xff0c;我突然有一个很强的…

OpenGL3.3_C++_Windows(32)

demo SSAO SSAO 环境光照(Ambient Lighting)&#xff1a;光的散射&#xff0c;我们通过一个固定的常量作为环境光的模拟&#xff0c;但是这种固定的环境光并不能很好模拟散射&#xff0c;因为环境光不是一成不变的&#xff0c;环境光遮蔽&#xff1a;让&#xff08;褶皱、孔洞…

Qt Designer,仿作一个ui界面的练习(一):界面的基本布局

初学不要太复杂&#xff0c;先做一个结构简单的&#xff0c;大致规划一下功能分区&#xff0c;绘制草图&#xff1a; 最终的效果&#xff1a; 界面主要由顶边栏、侧边栏、内容区构成。顶边栏左边是logo&#xff0c;右边是时钟显示。侧边栏最上边是切换按钮&#xff0c;用以动画…

Notcoin 即将空投:你需要知道什么

Notcoin 于 2024 年 1 月推出&#xff0c;是 Telegram 上的一款边玩边赚游戏&#xff0c;用户可以通过点击硬币图标获得 Notcoin 代币 (NOT) 形式的奖励。NOT 建立在开放网络区块链&#xff08;称为“TON 区块链”&#xff09;上&#xff0c;由 Open Builders 创始人 Sasha Plo…

鸿蒙配置Version版本号,并获取其值

app.json5中配置版本号&#xff1a; 获取版本号&#xff1a; bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION).then((bundleInfo) > {let versionName bundleInfo.versionName; //应用版本号}).catch((error: BusinessE…