Android -- selector&&StateListDrawable
selector
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 触摸时并且当前窗口处于交互状态 -->
<item android:state_pressed="true" android:state_window_focused="true" android:drawable= "@drawable/pic1" />
<!-- 触摸时并且没有获得焦点状态 -->
<item android:state_pressed="true" android:state_focused="false" android:drawable="@drawable/pic2" />
<!--选中时的图片背景-->
<item android:state_selected="true" android:drawable="@drawable/pic3" />
<!--获得焦点时的图片背景-->
<item android:state_focused="true" android:drawable="@drawable/pic4" />
<!-- 窗口没有处于交互时的背景图片 -->
<item android:drawable="@drawable/pic5" />
</selector>
StateListDrawable
该类定义了不同状态值下与之对应的图片资源,即我们可以利用该类保存多种状态值,多种图片资源。
public void addState (int[] stateSet, Drawable drawable)
给特定的状态集合设置drawable图片资源,参考前面的selector的xml文件,我们利用代码去构建一个相同的StateListDrawable类对象
//初始化一个空对象
StateListDrawable stalistDrawable = new StateListDrawable();
//获取对应的属性值 Android框架自带的属性 attr
int pressed = android.R.attr.state_pressed;
int window_focused = android.R.attr.state_window_focused;
int focused = android.R.attr.state_focused;
int selected = android.R.attr.state_selected; stalistDrawable.addState(new int []{pressed , window_focused}, getResources().getDrawable(R.drawable.pic1));
stalistDrawable.addState(new int []{pressed , -focused}, getResources().getDrawable(R.drawable.pic2);
stalistDrawable.addState(new int []{selected }, getResources().getDrawable(R.drawable.pic3);
stalistDrawable.addState(new int []{focused }, getResources().getDrawable(R.drawable.pic4);
//没有任何状态时显示的图片,我们给它设置我空集合
stalistDrawable.addState(new int []{}, getResources().getDrawable(R.drawable.pic5);
上面的“-”负号表示对应的属性值为false
public boolean isStateful ()
表明该状态改变了,对应的drawable图片是否会改变。(在StateListDrawable类中,该方法返回为true,显然状态改变后,我们的图片会跟着改变。)
状态
android:state_selected 选中
android:state_focused 获得焦点
android:state_pressed 点击
android:state_enabled 设置是否响应事件,指所有事件
selected和focused的区别
- selected不同于focus状态,通常在AdapterView类群下例如ListView或者GridView会使某个View处于selected状态,并且获得该状态的View处于高亮状态。
- 一个窗口只能有一个视图获得焦点(focus),而一个窗口可以有多个视图处于”selected”状态中。
- focused状态一般是由按键操作引起的;
- pressed状态是由触摸消息引起的;
- selected则完全是由应用程序主动调用setSelected()进行控制。
分析
当View任何状态值发生改变时,都会调用refreshDrawableList()方法去更新对应的背景Drawable对象。
//主要功能是根据当前的状态值去更换对应的背景Drawable对象
public void refreshDrawableState() {
mPrivateFlags |= DRAWABLE_STATE_DIRTY;
//所有功能在这个函数里去完成
drawableStateChanged();
//...
} // 获得当前的状态属性--- 整型集合 ; 调用Drawable类的setState方法去获取资源。
protected void drawableStateChanged() {
//该视图对应的Drawable对象,通常对应于StateListDrawable类对象
Drawable d = mBGDrawable;
if (d != null && d.isStateful()) { //通常都是成立的
//getDrawableState()方法主要功能:会根据当前View的状态属性值,将其转换为一个整型集合
//setState()方法主要功能:根据当前的获取到的状态,更新对应状态下的Drawable对象。
d.setState(getDrawableState());
}
} public final int[] getDrawableState() {
if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
return mDrawableState;
} else {
//根据当前View的状态属性值,将其转换为一个整型集合,并返回
mDrawableState = onCreateDrawableState(0);
mPrivateFlags &= ~DRAWABLE_STATE_DIRTY;
return mDrawableState;
}
}
setState()
//如果状态态值发生了改变,就回调onStateChange()方法。
public boolean setState(final int[] stateSet) {
if (!Arrays.equals(mStateSet, stateSet)) {
mStateSet = stateSet;
return onStateChange(stateSet);
}
return false;
}
判断状态值是否发生了变化,如果发生了变化,就调用onStateChange()方法进一步处理。
//状态值发生了改变,我们需要找出第一个吻合的当前状态的Drawable对象
protected boolean onStateChange(int[] stateSet) {
//要找出第一个吻合的当前状态的Drawable对象所在的索引位置, 具体匹配算法请自己深入源码看看
int idx = mStateListState.indexOfStateSet(stateSet);
...
//获取对应索引位置的Drawable对象
if (selectDrawable(idx)) {
return true;
}
...
}
根据新的状态值,从StateListDrawable实例对象中,找到第一个完全吻合该新状态值的索引下标处 ; 继而,调用selectDrawable()方法去获取索引下标的当前Drawable对象。
public boolean selectDrawable(int idx)
{
if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
//获取对应索引位置的Drawable对象
Drawable d = mDrawableContainerState.mDrawables[idx];
...
mCurrDrawable = d; //mCurrDrawable即使当前Drawable对象
mCurIndex = idx;
...
} else {
...
}
//请求该View刷新自己,这个方法我们稍后讲解。
invalidateSelf();
return true;
}
Drawable.Callback
public static interface Callback {
//如果Drawable对象的状态发生了变化,会请求View重新绘制,
//因此我们对应于该View的背景Drawable对象能够”绘制出来”.
public void invalidateDrawable(Drawable who);
public void scheduleDrawable(Drawable who, Runnable what, long when);
public void unscheduleDrawable(Drawable who, Runnable what);
}
Android框架View类继承了该接口,同时实现了这三个函数的默认处理方式,其中invalidateDrawable()方法如下:
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource
{
...
//Invalidates the specified Drawable.
//默认实现,重新绘制该视图本身
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) { //是否是同一个Drawable对象,通常为真
final Rect dirty = drawable.getBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
//重新请求绘制该View,即重新调用该View的draw()方法 ...
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
}
}
...
}
因此,我们的Drawable类对象必须将View设置为回调对象,否则,即使改变了状态,也不会显示对应的背景图。
Drawable d ; // 图片资源
d.setCallback(View v) ; // 视图v的背景资源为 d 对象
我是天王盖地虎的分割线
参考:http://blog.csdn.net/qinjuning/article/details/7474827
Android -- selector&&StateListDrawable的更多相关文章
- android selector 背景选择器的使用, button (未点击,点击,选中保持状态)效果实现
android selector 背景选择器的使用, button (未点击,点击,选中保持状态)效果实现 首先看到selector的属性: android:state_focus ...
- 我的Android进阶之旅------>Android中StateListDrawable支持的状态
Android中StateListDrawable支持的状态 android:state_active 代表是否处于激活状态 android:state_checked 代表是否处于已勾选状态 an ...
- Android的stateListDrawable,layerDawable,clipdrawable,AnimationDarwable介绍-android学习之旅(五十五)
StatelistDrawable资源 代码示例 <?xml version="1.0" encoding="utf-8"?> <select ...
- Android Selector原理
android的selector对于android开发者而言再熟悉不过了,只要定义一个drawable目录下定义一个selector的xml文件,在布局文件中引用这个xml文件或者在代码中setBac ...
- Android开发 StateListDrawable详解
前言 StateListDrawable是与xml中的selector属性对应代码实现类,它需要配合GradientDrawable的使用,如果你还不了解GradientDrawable可以参考我的另 ...
- 【原创】Android selector选择器无效或无法正常显示的一点研究
想将LinearLayout作为一个按钮,加上一个动态背景,按下的时候,背景变色,这个理所当然应该使用selector背景选择器来做: <LinearLayout android:id=&quo ...
- android selector 开始自定义样式
Selector的结构描述: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:a ...
- android selector(转)
Selector的结构描述: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:a ...
- android selector(如对TextView点击样式改变)
selector 1.selector 从单词的意思来说:选择者,选择器,就是对你的目标的控制. 从API来说: A controller for the selection of Selectabl ...
随机推荐
- 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem F. Finance 模拟题
Problem F. Finance 题目连接: http://codeforces.com/gym/100714 Description The Big Boss Company (BBC) pri ...
- 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem D. Distance 迪杰斯特拉
Problem D. Distance 题目连接: http://codeforces.com/gym/100714 Description In a large city a cellular ne ...
- vue项目开发之v-for列表渲染的坑
不知道大家在用vue开发的过程中有没有遇到过在使用v-for的时候会出现大片的黄色警告,比如下图: 其实这是因为没有写key的原因 :key是为vue的响应式渲染提供方法,在列表中单条数据改变的情况下 ...
- spring-boot 速成(6) 整合disconf
spring-boot虽然不推荐使用xml文件做为配置文件,但是并没有把路堵死,所以与disconf的整合,仍旧可以沿用之前的xml方式来处理. 一.在Application类上用注解导入xml pa ...
- Wingdings 2 符号编码对照表
http://blog.csdn.net/linux7985/article/details/5030754 符号 编码 HTML 代码 符号 编码 HTML 代码 ! ! " &q ...
- 性能优化:使用SparseArray代替HashMap<Integer,Object>(转)
HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...
- linux-socket connect阻塞和非阻塞模式 示例
~/cpp$ ./connect 192.168.1.234 1234 kkkk block mode: ubuntu 14.04 : time used:21.0.001053s connect ...
- Revit MEP API找到连接器连接的连接器
通过conn.AllRefs;可以找到与之连接的连接器. //连接器连接的连接器 [TransactionAttribute(Autodesk.Revit.Attributes.Transaction ...
- MyEclipse10安装Log4E插件
一. Log4E插件下载 下载地址:http://log4e.jayefem.de/content/view/3/2/ 二.安装Log4E插件 将下载下来的压缩包解压缩,如下图所示: 解压缩生成的[d ...
- JBPM使用方法、过程记录
一.How to call Web Service Using JBPM 5, designer https://204.12.228.236/browse.php?u=ObFK10b3HDFCQUN ...