把下面的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中