編輯:關於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)在ListView中添加如下屬性代碼
[html]
android:state_selected選中
android:state_focused獲得焦點
android:state_pressed點擊
android:state_enabled設置是否響應事件,指所有事件
Android平台版本和設備碎片化很嚴重,因此從Win32平台移植到Android平台會有很多問題,下面是我們歸納的從Win32平台移植到Android平台遇到的一些問題
前言:我相信”天生我才必有用”這句話,每個人都有他的作用,也許他的作用相對其他人來不是很明顯,也許他的作用也就是取悅別人,但是請不要忘記,可以通過
標題固定頁卡滑動效果的實現,先看一下效果圖。當滑動下面內容頁卡的時候,上面的標題固定。下面具體講一下怎麼實現這種效果。在項目中使用了v4包的viewpager組件。我們需
在開發中UI布局是我們都會遇到的問題,隨著UI越來越多,布局的重復性、復雜度也會隨之增長。Android官方給了幾個優化的方法,但是網絡上的資料基本上都是對官方資料的翻譯