Android的Drawable源碼分析

Drawable源碼分析

Android中會常常使用Drawable做爲某一個View的背景,既能夠是外部圖片加載的,也能夠是本身經過xml繪製的,也能夠是自定義一個Drawable子類實現的。那麼咱們就從Drawable類開始,分析其在Android中是如何完成這些功能的。
本系列文章以API28做爲源碼分析基準。
該系列文章初步設計爲8篇,更新時間待定。。
經過查看Drawable子類,能夠發現其擁有41個子類(其中包含了一部分Compat),可見Drawable在Android中地位仍是十分重要的,系統中提供了大量的不一樣類型的Drawable供開發者使用。根據源碼中的註釋,能夠看到Drawable主要能夠分爲以下幾個類別數組

(1) Bitmap: 最簡單的,用於加載png/jpeg.
(2) Nine Patch:png的拓展,能夠拉伸並在其中放置信息
(3) Vector: xml中定義的一系列點線集合,拉伸幾乎不會有畫質損失
(4) Shape: 代替原始的bitmap,在一些改變大小的場景比較合適
(5) Layers: 複合圖,多個圖繪製在一塊兒
(6) States: 複合圖,按照不一樣狀態進行顯示
(7) Levels: 複合圖,根據層級進行選擇
(8) Scale:  具備單個子級可繪製的複合可繪製文件,其整體大小根據當前級別進行修改
複製代碼

(一)基礎信息

經過AS的structure窗口,能夠看到Drawable類的組成,主要包含五大部分
1.interface Callback:當咱們須要實現帶動畫效果的圖時,須要實現該接口
2.public static abstract class ConstantState:保存圖的狀態,這個是比較關鍵的類。舉個例子,當咱們使用同一個圖加載的Drawable時,它們都對應同一個ConstantState,當改變其中一個View的顯示狀態時,其餘引用該圖的View也會受到影響。若是想像深拷貝那樣來一個Drawable,則能夠經過調用mutate方法後再對Drawable進行處理,則他們之間不會相互影響。這裏的原理在後續的文章中會涉及。
3.一些處理方法Method
4.一些property
5.一些Field
Field和Property的區別:Field是外部不可見的,沒有set/get方法的屬性;Property是存在set/get方法,外部能夠接觸到的屬性bash

(二)關鍵方法

全局搜索,能夠發現整個Drawable類只有幾個方法是abstract的,是須要子類去實現的,其餘大部分方法都已經有了具體實現,子類只須要去調用就能夠得到相應的功能。
1.draw方法
抽象方法。具體的繪製工做交給子類去完成。而且繪製的時候會根據其bound參數進行繪製,若是沒有設置任何bound參數,則該drawable的可視面積爲0。具體緣由爲Drawable類初始化時有一個Rect類表示Drawable的繪製區域,若是沒有設置bound,則該Rect爲0源碼分析

private static final Rect ZERO_BOUNDS_RECT = new Rect();
private Rect mBounds = ZERO_BOUNDS_RECT;
//經過該方法改變Rect大小
public void setBounds(int left, int top, int right, int bottom) {
        Rect oldBounds = mBounds;

        if (oldBounds == ZERO_BOUNDS_RECT) {
            oldBounds = mBounds = new Rect();
        }

        if (oldBounds.left != left || oldBounds.top != top ||
                oldBounds.right != right || oldBounds.bottom != bottom) {
            if (!oldBounds.isEmpty()) {
                // first invalidate the previous bounds
                invalidateSelf();
            }
            mBounds.set(left, top, right, bottom);
            onBoundsChange(mBounds);//protected空方法,子類實現當大小發生改變時的邏輯
        }
    }
複製代碼

2.setAlpha方法
抽象方法。用於設置透明度,取值0-255,255表示徹底不透明,0表示透明。
3.setColorFilter方法
抽象方法。若是設置了ColorFilter,則Drawable中的每個像素都會進行相應的計算,變成對應的顏色。經過設置null來移除ColorFilter。 該方法通常都是利用ColorMatrixColorFilter來實現,傳遞一個4*5的數組表示運算矩陣。
4.getIntrinsicWidth等方法
基類中返回-1,若是子類實現,須要更新其數值。諸如BitmapDrawable就在該方法返回實際寬度。
5.getMinimumWidth等方法
該方法返回最小值,會調用getIntrinsicWidth方法和0比較,返回值非負。當用在背景時,該值建議爲視圖寬度的最小值。
6.mutate方法
字面意思:改變。基類中直接返回這個Drawable動畫

public @NonNull Drawable mutate() {
        return this;
    }
複製代碼

前面咱們講過ConstantState類是一個抽象類,用於記錄一個Drawable的各種屬性,在Drawable的子類中,也一樣有一個ConstantState的靜態子類實現。這樣,當調用mutate方法的時候,就會建立一個新的ConstantState給Drawable使用,從而不和其餘Drawable共用同一個State從而相互影響。 從mutate方法的註釋咱們也能看出一二ui

Make this drawable mutable. This operation cannot be reversed. A mutable
drawable is guaranteed to not share its state with any other drawable.
This is especially useful when you need to modify properties of drawables
loaded from resources. By default, all drawables instances loaded from
the same resource share a common state; if you modify the state of one
instance, all the other instances will receive the same modification.
讓Drawable可變。這個操做不可逆。一個可變的Drawable不和其餘Drawable共享狀態。
當你須要改變從resource中加載的drawable屬性時十分有用。
默認狀況下,從同一個資源中加載的drawable共享一個狀態
若是你改變了一個實例的狀態,那麼其餘全部的實例都會受到影響
複製代碼

(三)關鍵類

1.StateSet類
該類看名字就能夠猜出是表示View的狀態的集合,其中定義了View的各個狀態(正整數)
在Drawable類中,有一個成員變量mStateSet,能夠看到是數組形式存在的this

private int[] mStateSet = StateSet.WILD_CARD;
//對應的get/set方法
public boolean setState(@NonNull final int[] stateSet) {
        if (!Arrays.equals(mStateSet, stateSet)) {
            mStateSet = stateSet;
            return onStateChange(stateSet);//子類實現,當狀態變化時的邏輯
        }
        return false;
    }
public @NonNull int[] getState() {
        return mStateSet;
    }
//StateSet類中的變量
//定義一個保存狀態的數組,當諸如StateListDrawable子類使用時,能夠將狀態保存在其中
public static final int[] WILD_CARD = new int[0];
複製代碼

2.ConstantState類
直白翻譯就是常量狀態類。該類用於保存一些Drawable之間共享的屬性和數據。其中提供了一些抽象方法供子類實現。
public abstract @NonNull Drawable newDrawable(); //根據當前狀態建立一個新的Drawable對象,還有其餘的重載方法spa

那麼mutate和newDrawable有啥區別?mutate方法會建立一個一樣的ConstantState給Drawable,相似於深拷貝,這樣改變mutate的drawable屬性就不會影響其餘drawable;而newDrawable建立出來的仍是使用一樣的ConstantState屬性,是會相互影響的。翻譯

3.PorterDuff類
以兩個大佬名字命名的類,描述了12種合成操做符,表示如何控制源與目標的顏色合成結果。設計

以上就是Drawable基類須要瞭解的一些基礎知識,下一篇咱們將從最簡單的ColorDrawable開始分析每個子類的具體實現。code

相關文章
相關標籤/搜索