Android Selector原理
android的selector对于android开发者而言再熟悉不过了,只要定义一个drawable目录下定义一个selector的xml文件,在布局文件中引用这个xml文件或者在代码中setBackgroundDrawable的时候使用此xml就可以实现控件按下或有焦点等不同状态的效果。
那么setBackgroundDrawable后为什么可以实现这个功能呢?
首先要了解一个Drawable类,Drawable是一个抽象的可绘制的图片类,这个类可以从一个本地路径中创建一个图片,也可以使用从定义好的xml中创建,他们分别对应Drawable的createFromPath和createFromXml函数,其中createFromPath是从路径中创建一个Bitmap对象并将它转换成BitmapDrawable,而createFromXml是从xml中定义的标签,例如selector的话就创建StateListDrawable对象,shape的话就创建GradientDrawable对象,color的话就创建ColorDrawable......而BitmapDrawable、StateListDrawable、GradientDrawable都是从Drawable类中派生而来。其中StateListDrawable类就是实现selector中定义的样式的Drawable.
其次我们看Drawable怎么跟View关联的。
Drawable类有维护了一个控件的不同状态的变量mStateSet,当View.setBackgroundDrawable时,会调用Drawable的isStateful函数判断是否有不同状态的,StateListDrawable返回的true,如果是有状态的就会将view的状态赋值给drawable即d.setState(getDrawableState());
d.setState(getDrawableState());
}
同时将传入的Drawable作为背景的Drawable.当控件接收到touch事件时会调用refreshDrawableState更新控件状态,同时也会更新背景的Drawable的状态
protected void drawableStateChanged() {
Drawable d = mBGDrawable;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
}
然后会调用invalidateDrawable这个回调函数来刷新界面,同时调用draw函数实现绘制。
再次我们来看实现Selector功能的Drawable即StateListDrawable是如何实现Selector功能的。
上面我们己经看到在View状态改变的时候,会调用Drawable的setState函数。在Drawable中是这样实现setState的
public boolean setState(final int[] stateSet) {
if (!Arrays.equals(mStateSet, stateSet)) {
mStateSet = stateSet;
return onStateChange(stateSet);
}
return false;
}
它在改变状态的时候会调用onStateChage来通知状态己经改变了。而StateListDrawable是继承Drawable的子类它复写了onStateChage函数
protected boolean onStateChange(int[] stateSet) {
int idx = mStateListState.indexOfStateSet(stateSet);
if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states "
+ Arrays.toString(stateSet) + " found " + idx);
if (idx < 0) {
idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
}
if (selectDrawable(idx)) {
return true;
}
return super.onStateChange(stateSet);
}
从上面的实现可以看到它在改变状态的时候会调用selectDrawable来选择一个当前状态的drawable,这就是实现的关键了。StateListDrawable继承了DrawableContainer而DrawableContainer继承了Drawable,StateListState是StateListDrawable的内部类,它就是保存selector中定义的不同状态的drawable的实现,它提供了addStateSet函数来增加某个状态下对应的drawable对象并将它保存在mStateSets变量中,而indexOfStateSet函数则是查找某个状态下对应的drawable。selectDrawable是DrawableContainer的类,它是根据传入的状态的索引来找到对应的drawable来当作当前状态下的drawable。
OK,现我我们终于能理解为什么selector是如何实现不同状态不同样式了。View使用Drawable来实现背景图,selector对应StateListDrawable,当view状态改变时,会改变drawable的状态,StateListDrawable在改变状态时会根据当前状态选择对应的drawable,这样在view绘制时会调用drawable的draw函数,StateListDrawable draw的是当前状态对应的drawable。
Android Selector原理的更多相关文章
- Android root 原理
Android root 原理 0x00 关于root linux和类Unix系统的最初设计都是针对多用户的操作系统,对于用户权限的管理很非常严格的,而root用户(超级用户)就是整个系统的唯一管理员 ...
- NFC(6)NFC编程的几个重要类,NFC硬件启动android应用原理
用于NFC编程的几个重要类 Tag NFC 标签 NfcAdapter Nfc 的适配类 NdefMessage 描述NDEF格式的信息 NdefRecord 描述NDEF信息的一个信息段,类似tab ...
- android selector 背景选择器的使用, button (未点击,点击,选中保持状态)效果实现
android selector 背景选择器的使用, button (未点击,点击,选中保持状态)效果实现 首先看到selector的属性: android:state_focus ...
- android的原理,为什么不需要手动关闭程序
转自android的原理,为什么不需要手动关闭程序 不用在意剩余内存的大小,其实很多人都是把使用其他系统的习惯带过来来了. Andoird大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制 ...
- Java NIO系列教程(七) selector原理 Epoll版的Selector
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- 【转】Android Activity原理以及其子类描述,androidactivity
Android Activity原理以及其子类描述,androidactivity 简介 Activity是Android应用程序组件,实现一个用户交互窗口,我们可以实现布局填充屏幕,也可以实 ...
- 传智播客学习之Android运行原理 (转)
传智播客学习之Android运行原理 (2010-03-20 22:45:15) 转载▼ 今天终于忙里偷闲,和大家探讨一下android技术,第一次听到3G应该追溯到大学三年级的时候了,记得当时现代通 ...
- Android ADB原理及常用命令
Android调试桥(ADB, Android Debug Bridge)是一个Android命令行工具,包含在SDK 平台工具包中,adb可以用于连接Android设备,或者模拟器,实现对设备的控制 ...
- 【原创】Android selector选择器无效或无法正常显示的一点研究
想将LinearLayout作为一个按钮,加上一个动态背景,按下的时候,背景变色,这个理所当然应该使用selector背景选择器来做: <LinearLayout android:id=&quo ...
随机推荐
- Android support library支持包常用控件介绍(二)
谷歌官方推出Material Design 设计理念已经有段时间了,为支持更方便的实现 Material Design设计效果,官方给出了Android support design library ...
- ROS(indigo)国外开源示例包括多机器人控制等基于V-Rep和Gazebo的仿真
ROS(indigo)国外开源示例包括多机器人的V-Rep和Gazebo仿真等 1 micros_swarm_framework 使用超级经典的stage. http://wiki.ros.org/m ...
- lk中内联调用的dsb()
lk中内联调用的dsb() 比如lk的uart_dm_init()函数就调用了dsb() /* Configure the uart clock */ clock_config_uart_dm(id) ...
- qualcomm memory dump 抓取方法
Memory dump是系统出现crash时常用的分析故障原因的方法,qualcomm 各子系统运行时,为方便debug,都会开辟ram log和debug variable用于保存各系统运行信息及健 ...
- Android项目-高考作文-AsyncTask的不足
1, AsyncTask的不足. 从android4.0开始, 后台只允许一个AsyncTask执行, 如果当前的AsyncTask没有执行完毕, 那么当前的请求一直处于等待状态. 直到上一个执行完毕 ...
- JAVA内部类_2
(d)匿名内部类 如果只创建这个类的第一个对象,就无需命名. 由于构造器的名字必须与类名相同,而匿名类没有类名,所以匿名类没有构造器. 取而代之的是将构造器参数传递给超类构造器. 在内部类实现接口的时 ...
- 安卓手机与ROS通信遥控Gazebo中仿真机器人小车运动(ROS_indigo)
首先,先列出需要用到的一些文件: Gazebo中机器人模型及说明: http://wiki.ros.org/grizzly_simulator https://github.com/g/grizzly ...
- 调用awk的三种方式
调用awk的三种方式 调用awk有三种方式,一种为Shell命令行方式,另外两种是将awk程序写入脚本文件,然后执行该脚本文件.三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用awk, ...
- android官方技术文档翻译——Case 标签中的常量字段
本文译自androd官方技术文档<Non-constant Fields in Case Labels>,原文地址:http://tools.android.com/tips/non-co ...
- Zookeeper Java客户端API的使用
1. 原生api 具体查看下面github代码 2. ZkClient ZkClient是Github上一个开源的ZooKeeper客户端.ZkClient在ZooKeeper原生 A ...