Android Selector原理

來源:互聯網
上載者:User

標籤:lists   標籤   cte   ring   raw   container   selector   androi   檔案   

 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原理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.