Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的Selector的原理及用法

Android中的Selector的原理及用法

編輯:關於Android編程

 

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());

if (d.isStateful()) {

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主要是用來改變ListView和Button控件的默認背景。其使用方法可以按一下步驟來設計:(以在mylist_view.xml為例)

1.創建mylist_view.xml文件

首先在res目錄下新建drawable文件夾,再在新建的drawable文件夾中新建mylist_view.xml,其目錄結構為:res/drawable/mylist_view.xml。

2.根據具體需求編輯mylist_view.xml文件

新建mylist_view.xml文件後,在沒有添加任何屬性時其內部代碼結構為:

 

[html] 
  1.  
  2. 下面就可以根據項目需求,在其內部定義為自己想要的樣式了,主要屬性如下: [html] view plaincopy
    1. android:drawable=@drawable/pic1 />
    2. 3.引用mylist_view.xml文件

      三種方法可以來引用剛才創建的文件:

      (1)在ListView中添加如下屬性代碼

       

      [html]
      1. android:listSelector=@drawable/mylist_view (2)在ListView的item界面中添加如下屬性代碼
        [html]
        1. android:background=@drawable/mylist_view (3)利用JAVA代碼直接編寫 [java] view plaincopy
          1. Drawable drawable = getResources().getDrawable(R.drawable.mylist_view);
          2. listView.setSelector(drawable); 為了防止列表拉黑的情況發生,需要在ListView中添加以下的屬性代碼 [html
            1. android:cacheColorHint=@android:color/transparent 屬性介紹:

              android:state_selected選中

              android:state_focused獲得焦點

              android:state_pressed點擊

              android:state_enabled設置是否響應事件,指所有事件

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved