把下面的XML文件保存成你本身命名的.xml文件(好比list_item_bg.xml),在系统使用时根据ListView中的列表项的状态来使用相应的背景图片。drawable/item_bg.xml java
java代码: <?xml version="1.0" encoding="utf-8" ?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 默认时的背景图片 --> <item android:drawable="@drawable/pic1" /> <!-- 没有焦点时的背景图片 --> <item android:state_window_focused="false" android:drawable="@drawable/pic1" /> <!-- 非触摸模式下得到焦点并单击时的背景图片 --> <item android:state_focused="true" android:state_pressed="true" android:drawable= "@drawable/pic2" /> <!-- 触摸模式下单击时的背景图片 --> <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/pic3" /> <!--选中时的图片背景 --> <item android:state_selected="true" android:drawable="@drawable/pic4" /> <!--得到焦点时的图片背景 --> <item android:state_focused="true" android:drawable="@drawable/pic5" /> </selector>经常使用的就这些了
设置ListView等控件的选择器方式:
第一种:是在 xml 文件中的 listview 控件中配置android:listSelector=”@drawable/list_item_bg
第二种:或者在 listview 的item中添加属性 android:background=“@drawable/list_item_bg” 便可实现,或者在Java 代码中使用: android
Drawable drawable = getResources().getDrawable(R.drawable.list_item_bg); ListView.setSelector(drawable); //一样的效果。可是这样会出现列表有时候为黑的状况,须要加上:android:cacheColorHint=” @android :color/transparent” 使其透明。
其次再来看看Button的一些背景效果:
android:state_selected是选中
android:state_focused是得到焦点
android:state_pressed是点击
android:state_enabled是设置是否响应事件,指全部事件
根据这些状态一样能够设置button的selector效果。也能够设置selector改变button中的文字状态。
button还能够实现更复杂的效果,例如渐变啊等等。也就是说在selector的xml文件里能够加入shape属性 算法
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> / <item android:state_pressed="true">//定义当button 处于pressed 状态时的形态。 <shape> <gradient android:startColor="#8600ff" /> <stroke android:width="2dp" android:color="#000000" /> <corners android:radius="5dp" /> <padding android:left="10dp" android:top="10dp" android:bottom="10dp" android:right="10dp"/> </shape>
前面说的xml文件,最终会被Android框架解析成StateListDrawable类对象
StateListDrawable类介绍
该类定义了不一样状态值下与之对应的图片资源,即咱们能够利用该类保存多种状态值,多种图片资源。经常使用方法为:
public void addState (int[] stateSet, Drawable drawable)
功能: 给特定的状态集合设置drawable图片资源 框架
//初始化一个空对象 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
通常来讲,Android框架为View定义了四种不一样的状态,这些状态值的改变会引起View相关操做,例如:更换背景图片、是否
触发点击事件等;视图几种不一样状态含义见下图
函数
其中selected和focused的区别有以下几点:
1,咱们经过查看setSelected()方法,来获取相关信息。
SDK中对setSelected()方法----对于与selected状态有以下说明:
public void setSelected (boolean selected)
Since: APILevel 1
Changes the selection state of this view. Aview can be selected or not. Note that selection is not the same as
focus. Views are typically selected in the context of an AdapterView like ListView or GridView ;the selected view is
the view that is highlighted.
Parameters selected true if the view must be selected, false otherwise
由以上可知:selected不一样于focus状态,一般在AdapterView类群下例如ListView或者GridView会使某个View处于
selected状态,而且得到该状态的View处于高亮状态。
一个窗口只能有一个视图得到焦点(focus),而一个窗口能够有多个视图处于”selected”状态中。
总结:focused状态通常是由按键操做引发的;
pressed状态是由触摸消息引发的;
selected则彻底是由应用程序主动调用setSelected()进行控制。
例如:当咱们触摸某个控件时,会致使pressed状态改变;得到焦点时,会致使focus状态变化。因而,咱们能够经过这种
更新后状态值去更新咱们对应的Drawable对象了。
经过看View源码知道根据状态值的改变去绘制/显示对应的背景图
当View任何状态值发生改变时,都会调用refreshDrawableList()方法去更新对应的背景Drawable对象。 this
//路径:\frameworks\base\core\java\android\view\View.java /* Call this to force a view to update its drawable state. This will cause * drawableStateChanged to be called on this view. Views that are interested * in the new state should call getDrawableState. */ //主要功能是根据当前的状态值去更换对应的背景Drawable对象 public void refreshDrawableState() { mPrivateFlags |= DRAWABLE_STATE_DIRTY; //全部功能在这个函数里去完成 drawableStateChanged(); ... } /* This function is called whenever the state of the view changes in such * a way that it impacts the state of drawables being shown. */ // 得到当前的状态属性--- 整型集合 ; 调用Drawable类的setState方法去获取资源。 protected void drawableStateChanged() { //该视图对应的Drawable对象,一般对应于StateListDrawable类对象 Drawable d = mBGDrawable; if (d != null && d.isStateful()) { //一般都是成立的 //getDrawableState()方法主要功能:会根据当前View的状态属性值,将其转换为一个整型集合 //setState()方法主要功能:根据当前的获取到的状态,更新对应状态下的Drawable对象。 d.setState(getDrawableState()); } } /*Return an array of resource IDs of the drawable states representing the * current state of the view. */ 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; } }Step 1 、 setState()函数原型 ,
//若是状态态值发生了改变,就回调onStateChange()方法。 public boolean setState(final int[] stateSet) { if (!Arrays.equals(mStateSet, stateSet)) { mStateSet = stateSet; return onStateChange(stateSet); } return false; }
该函数的主要功能: 判断状态值是否发生了变化,若是发生了变化,就调用onStateChange()方法进一步处理 spa
Step 2 、onStateChange()函数原型:
该函数位于 frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中
.net
//状态值发生了改变,咱们须要找出第一个吻合的当前状态的Drawable对象 protected boolean onStateChange(int[] stateSet) { //要找出第一个吻合的当前状态的Drawable对象所在的索引位置, 具体匹配算法请本身深刻源码看看 int idx = mStateListState.indexOfStateSet(stateSet); ... //获取对应索引位置的Drawable对象 if (selectDrawable(idx)) { return true; } ... }该函数的主要功能: 根据新的状态值,从StateListDrawable实例对象中,找到第一个彻底吻合该新状态值的索引下标处 ; 继而,调用selectDrawable()方法去获取索引下标的当前Drawable对象。具体查找算法在 mStateListState.indexOfStateSet(stateSet) 里实现了。基本思路是:查找第一个能彻底吻合该新状态值的索引下标,若是找到了,则当即返回。 具体实现过程,只好看看源码
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对象,并保存在mCurrDrawable中