美文网首页
对 Drawable 的理解

对 Drawable 的理解

作者: jkwen | 来源:发表于2021-07-06 23:04 被阅读0次

    Picasso 图片加载展示的最后一步是传入 PicassoDrawable 对象,调用 ImageVIew 的 setImageDrawable 方法。这其实和我们平时用 ImageView 展示图片有些不同。项目中使用,更多的是调用 setImageResource 来传入一个资源 ID,或者在 xml 布局中指定资源。

    这使得我想去探究下这两个方法调用有何不同,以及对 xx-Drawable 理解。

    Drawable

    代表着这样一个东西,它有绘制的功能,我们经常用它来表示图片,形状,资源,并最终展示到屏幕上。也可以这么理解,它是仅保留了 draw 功能的 View。

    因为是抽象类,所以有几个抽象方法在子类里是要实现的,

    • setAlpha
    • setColorFilter
    • draw

    Drawable 实现的形式有很多,意味着对应的子类也有很多,具体的形式有,

    1. Bitmap
    2. Nine Patch
    3. Vector
    4. Shape
    5. Layers
    6. States
    7. Levels
    8. Scale

    这个类应该和我们 res 包下面的 drawable 里的 xml 文件是对应的。例如定义一个 shape 标签的 drawable 文件就对应着 Shape 形式,其他应该类似能对应上(当然这基于猜测,有待后续分析验证)

    就我理解的 Drawable 这个抽象类,重点应该就在 draw 方法的实现,所以如果想要展示一些东西,可以利用 Drawable 绘制,因为通过 draw 方法能持有画布引用,我们暂且不管画布如何将内容展示在屏幕上,就认准有了画布就能画东西,画的内容就能展示出来。

    BitmapDrawable

    PicassoDrawable 继承自 BitmapDrawable,它的特殊性在于包裹了一个 bitmap,这个 bitmap 的数据来源可以是文件,输入流,xml 或者直接 Bitmap 对象。显然是围绕 Bitmap 展开的,从 draw 方法可以看到最终调用 canvas.drawBitmap 来绘制。

    由此分析 PicassoDrawable 的本质也是类似,也就是说加载过来的 Bitmap 最终会以 canvas.drawBitmap 的方式最终展现。

    ImageView

    再回过头来看下 setImageDrawable 方法,

    public void setImageDrawable(@Nullable Drawable drawable) {
        if (mDrawable != drawable) {
            mResource = 0;
            updateDrawable(drawable);
            invalidate();
        }
    }
    

    大致的思路是更新 mDrawable 对象,并触发后续的 onDraw 步骤。其实在 View 的工作流中,和展示最直接相关的也就是 onDraw 了,

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDrawable == null) {
            return;
        }
        if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
            mDrawable.draw(canvas);
        } else {
            final int saveCount = canvas.getSaveCount();
            canvas.save();
            canvas.translate(mPaddingLeft, mPaddingTop);
            if (mDrawMatrix != null) {
                canvas.concat(mDrawMatrix);
            }
            mDrawable.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    }
    

    从 ImageView 的 onDraw 方法中可以看出 mDrawable 其实是个很关键属性,要是不存在的话,onDraw 也就没事可做了。代码再往下执行,其实就是调用了 Drawable 的 draw 方法,结合前面以 BitmapDrawable 的为例的分析,最终就是 drawBitmap,所以最终图片得以展示。

    那么 setImageResource 方法呢?

    public void setImageResource(@DrawableRes int resId) {
        updateDrawable(null);
        mResource = resId;
        mUri = null;
        resolveUri();
        invalidate();
    }
    private void resolveUri() {
        if (mDrawable != null) {
            return;
        }
        Drawable d = null;
        if (mResource != 0) {
            d = mContext.getDrawable(mResource);
        } else if (mUri != null) {
            d = getDrawableFromUri(mUri);
        } else {
            return;
        }
        updateDrawable(d);
    }
    

    首先会将 mDrawable 置为空,接着通过 Context 对象将图片资源 ID 转为 Drawable 对象,然后更新给 mDrawable 对象,最后依然会触发 onDraw 方法的调用来完成绘制。

    由此可见,平常虽说直接引用图片资源,但实际会最终以 Drawable 的形式用来展示,资源形式不过便于我们开发使用罢了。

    至此,对 ImageView 我又有了新的理解,它之所以能展示图片,并不在于这个控件的特殊性,而在于 Drawable 的作用。

    相关文章

      网友评论

          本文标题:对 Drawable 的理解

          本文链接:https://www.haomeiwen.com/subject/ztpnultx.html