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 ...
随机推荐
- Java:使用匿名内部类在方法内部定义并启动线程
下面的代码展示了在一个方法中,通过匿名内部类定义一个Thread,并Override它的run()方法,之后直接启动该线程. 这样的代码可用于在一个类内部通过另起线程来执行一个支线任务,一般这样的任务 ...
- 【嵌入式开发】嵌入式 开发环境 (远程登录 | 文件共享 | NFS TFTP 服务器 | 串口连接 | Win8.1 + RedHat Enterprise 6.3 + Vmware11)
作者 : 万境绝尘 博客地址 : http://blog.csdn.net/shulianghan/article/details/42254237 一. 相关工具下载 嵌入式开发工具包 : -- 下 ...
- FFmpeg获取DirectShow设备数据(摄像头,录屏)
这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1. 列设备 ffmpeg -list_devic ...
- TableEdit UI_10
1.tableView的编辑的步骤: 1.让tableView处于编辑状态,(默认所有的cell都处于编辑状态,默认下的编辑样式是删除) 2.设置哪些cell可以编辑 3.设置编辑的样式(删除,插 ...
- Android Wear开发
Android Wear从2014年3月发布到现在已经从1.0发展到2.0(目前还没正式发布).其产品定位也发化了巨大变化,因为Android Wear 1.0通讯方式只有蓝牙,限定了系统,比较依赖手 ...
- [RDLC]一步一步教你使用RDLC(一)
一:加数据集,并且命名为Quotation,如下图所示: 二: 添加一张报表,命名为Quotation,如下图所示: 向报表中添加"表"这一项,如下图所示: 这时就弹出一个选择数据 ...
- (十二)UITableView的基本使用
UITableView之所以支持滚动,是因为继承自UIScrollView.默认是垂直滚动,性能极佳. UITableView的两种样式: 1.UITableViewStylePlain ...
- AWR報告詳解
AWR是Oracle 10g 版本 推出的新特性, 全称叫Automatic Workload Repository-自动负载信息库, AWR 是通过对比两次快照(snapshot)收集到的统计信息 ...
- [问与答]Python 中 __all__ 的作用 ?
你要是看Python的源码或者相关框架的源码,总是在 __init__.py 或者是源文件的开头看到一个 __all__ 变量的定义,今天就说说它的作用. orangleliu 问题出处 Can so ...
- 关于MySQL主从复制中UUID的警告信息
日期: 2014年5月23日 博客: 铁锚 最近在查看MariaDB主从复制服务器 Master 的错误日志时看到很多条警告信息,都是提示 UUID()函数不安全,可能 Slave 产生的值和 Mas ...