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的ScrollView和HorizontalScrollView-android学习之旅(四十一)
HorizontalScrollView和ScrollView简介 ScrollView和HorizontalScrollView都继承于FrameLayout组件,两个都是容器,前者为里面的组件添加 ...
- Android进阶(二十二)设置TextView文字水平垂直居中
设置TextView文字水平垂直居中 有2种方法可以设置TextView文字居中: 一:在xml文件设置:android:gravity="center" 二:在程序中设置:m_T ...
- UITableViewBase UI_09
1.UITableView API文档总结: 1.UITableView的父类时,UIScrollView,所以它是可以滚动的,但是只能在竖直方向滚动. 2.UITableView是iOS中 ...
- Socket层实现系列 — 信号驱动的异步等待
主要内容:Socket的异步通知机制. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了几个IO事件:状态改变事件.有数据可读事 ...
- Touch Handling in Cocos2D 3.x(二)
接受触摸 在Cocos2d 3.0中每一个CCNode和每一个CCNode的子类都可以接收触摸.你只需要开启一个选项.让我们在定制的初始化器里完成它.替换MainScene.m中init方法的代码: ...
- 9.7、Libgdx之振动器
(官网:www.libgdx.cn) 振动器允许你提醒手机用户. 振动器智能应用在Android设备中,需要特殊的权限: android.permission.VIBRATE 可以通过如下方式实现振动 ...
- JavaScript进阶(二)在一个JS文件中引用另一个JS文件
在一个JS文件中引用另一个JS文件 转载地址:http://blog.csdn.net/zndxlxm/article/details/7875787 方法一 在调用文件的顶部加入下例代码 ...
- Android官方技术文档翻译——IntelliJ 项目迁移
本文译自Android官方技术文档<Migrating from IntelliJ Projects>,原文地址:http://tools.android.com/tech-docs/ne ...
- Leetcode_96_Unique Binary Search Trees
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43198929 Given n, how many stru ...
- Salesforce 官方扫盲自学导航
Force.com Platform Fundamentals(新手入门的葵花宝典)www.salesforce.com/us/developer/docs/fundamentals/index_Le ...