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

相关文章
相关标签/搜索