安卓 Drawable源码分析简述

Drawable 是一种封装

View是对视图的封装, 构造成view tree, 然后由VireRootImpl与窗口进行交接.

一个View 的内部绘制的元素进行分解, 无非这几种:

(1)背景
(2)直接画在canvas上的绘制内容(即ondraw方法)
(3)children(即子view)
(4)什么fading/scrollbar之类.

这里的一切, 都是要绘制在draw(canvas)的参数canvas上面的.

这里的问题是: 当一个东西不用一个子view来封装的话, 那该用什么来处理呢?

由子view来绘制, 那不过也是让子view执行draw(canvas)而已.

对于非子view的东西, 我们要画在canvas上面, 有两种:

(1)直接执行canvas.drawBitmap/drawLine/drawPath之类方法
(2)一种就是执行drawable.draw(canvas)方法.

这一点, 最直观的, 可以在ImageView上得到验证.

总结一下, 一个view的三种绘制到canvas上的方式:

(1)由子view来绘制, 
    即: dispatchDraw(canvas,...)
        --->drawChild(canvas,...)
        --->child.draw(canvas,...)
    这样下去.
(2)直接通过Canvas的方法来绘制, 
    即 canvas.drawBitmap/drawLine/drawPath之类方法.
(3)通过 drawable.draw(canvas)来绘制. 
    在 Drawable的 draw(canvas)方法中, 
    我们要进行的是 对这个Drawable所封装的各个组成部分绘制到canvas上面.

实际上, Drawable 是对一些要绘制的东西的一个封装而已, 它是一个抽象类, 其draw方法是抽象方法.

我们可以自定义一些Drawable的子类, 当然framework已为我们定义了一些其子类, 这里不多说.

Drawable 的模块子类如何去重写?

几点关键处:

其一: 重写draw(canvas)方法—-这个上面说过了.
其二: Drawable中有一个内部类: ConstantState.
我们需要在自定义的Drawable中 也自定义一个内部类, 继承于它.
这个内部类的作用是: 
    其是对自定义Drawable的各个元素的封装, 
        并提供方法出来让与外部自定义Drawable进行交互.
这个东西 文字表达起来太抽象了, 具体见各个代码.
比如容易看得懂的, 比如 ClipDrawable 中的那个内部类, RotateDrawable 中的那个内部类.
----其实 LevelListDrawable/StateListDrawable 中的那个内部类 也并不是很麻烦, 
        只是看起来吓人而已.
其三: Drawable 本身给出的接口, 我们也需要去重写的, 这个就不多说了, 可以参考framework提供的那几个Drawable的子类.
其四: Drawable何时进行绘制? Drawable何时进行更新?

这个问题是Drawable的核心问题.

我们的界面的更新, 只有一个途径:

这里只从窗口开始说起:
    ...--->窗口
    --->ViewRootImpl绘制请求
    --->执行ViewRootImpl的performTravesals方法
    --->在performTravesals中, 
        进行深度遍历view tree上各个view结点的
            measure/layout/draw方法.
我们对Drawable的绘制, 
    实际都是在view的draw(canvas)中进行的drawable.draw(canvas)操作完成的.

现在问题来了, 我们代码中, 我们如何让Drawable来发起 invalidate这样的更新请求呢?

实际上, drawable中这么一个方法: invalidateSelf, 调用它, 会发出更新请求.

那么其原理是如何的?

这个就要从 Drawable.Callback 接口说起来了.(这个接口有三个方法, 具体见源码, 这里不列出来.)

语言表达能力有限, 那就不折腾了, 只提几处关键处:

(1)Drawable 中有一个 setCallback方法, 
    即我们可以为这个 Drawable 设置一个 Drawable.Callback对象, 
    即 为 Drawable 中的 mCallback 进行赋值.
(2)实现这个 Drawable.Callback 的类, 通常是两种类型的:
    一种是: View 实现了 Drawable.Callback 接口, 
        在其中的 invalidateDrawable 方法中, 调用了 view的invalidate方法 进行视图更新.
    一种是: Drawable 的各子类, 比如 ClipDrawable 等等. 

举 ClipDrawable 为例:

(1)ClipDrawable 所注册的 mCallback, 是视图View的.
    所以, 当 调用 ClipDrawable 时, 执行的是 View.invalidate方法, 
    然后在  View.draw方法中, 
        又执行到 ClipDrawable的 draw(canvas)方法 来完成绘制.
(2)在这个 ClipDrawable 的 draw(canvas)方法中, 
    会执行 mClipState.mDrawable.draw(canvas); 
        来完成把东西绘制到 canvas上的操作.
(3)当我们为mClipState.mDrawable赋值时, 
    我们会为这个mClipState.mDrawable置一个callback, 
        这个callback就是ClipDrawable自身.
    这一点在 ClipDrawable的用处表现并不明显, 
    但在AnimationDrawable等上面表现很明显, 
    为什么?
    因为AnimationDrawable在画完一个frame之后, 要画下一个frame的, 
    而要画下一个frame, 
    就需要通过Drawable.Callback的scheduleDrawable方法处理.
    由谁来发出画下一个frame的请求呢?
    当然应当由内部类对象中封装的刚进行了draw的mDrawable来调用了.
    所以, 我们应当把AnimationDrawable做为mCallback,
    注册给AnimationDrawable中内部类对象中所封装的各个drawable.

什么? 请等等….., mClipState 是什么东西? 其中的 mDrawable 是什么东西?

这个实际上 就是上面说过的, 这是 一个 ClipDrawable 的内部类对象, 
这个内部类 ClipState 继承自 Drawable.ConstantState 类.
这种内部类 实际上 就是对 这个Drawable子类 的一些特点的封装.
比如 ClipDrawable 是对一个 Drawable对象的剪切显示, 
    当我们 clipDrawable.setLevel(int)给出不同的值时, 剪切的区域会不同.
所以, 我们在 ClipDrawable 中定义一个 数据成员 mDrawable 来存放要剪切的Drawable对象.
在 这个 clipDrawable.setLevel(int) 操作, 是会调用到 onLevelChange 方法的, 
在这个 onLevelChange 方法中, 会调用 invalidateSelf 方法 进行视图更新的.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值