Android view绘制机制探究

首先,还是贴张图,这是我在网上看到的一张图,感觉它把view的整个流程都展现出来了

 

我们要用一个view,一般就是两种方式,

1.在局部文件里面 , 作为一个节点
2.在代码中 , 通过 LayoutInflater inflate() 加载 ; 然后父控件通过 addview inflate 出来的这个控件添加进来了 ~( 其实上一种方式本质上也是这样 )

ViewRoot

在所有 view 之上有一个 ViewRoot,我们 通过调用它的 performTraversals() 来判断是否需要调用 measure()layout(),draw() 这一系列函数 .大致是这样的

下面我们就假设view直接在ViewRoot之下(如果不在它下面的话就算是一个view的子控件)

OnMeasure()

首先 ,RootView 调用了 measure() 来测量大小 .
首先要确定自己的大小 , 通过 onMeasure(), 我们能重载的也是它 , 调用 setMeasuredDimension() 会为这个 view 设定自己的宽度 (mMeasuredWidth) 和高度 (mMeasuredHeigth), 若该 View ViewGroup, 则需在此处让子视图测量自己的大小 , 确保所有视图都测量无误 .( 通过 ViewGroup 提供的约束条件 )
在此过程中 , 会传入两个参数 ,widthMeasureSpec heightMeasureSpec, 分别是高度和宽度的测量规格 , 每个测量规格都由两部分组成 ,mode size,size 是默认设置为和父控件相同 ,mode 则分为三种 :
UNSPECIFIED( 不确定 ): 程序员可以任意设置大小
AT_MOST( 至多 ): 大小不能超过给定的大小 , specSize
EXACTLY( 精确 ): 大小只能为 specSize
下面是源码中的处理方式
 
    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
}

Tip:viewgroup 提供了measureChild() 来帮助测量子控件 .
Tip:getMeasureWidth() measure() 结束后就可以取到值 ,getWidth() 则要在 layout() 之后才能取到值 .getMeasureWidth() 的返回值是在 setMeasuredDimension() 时设置的 , getWidth() 的返回值则是通过视图右坐标减去左坐标计算而来 .

Onlayout()(ViewGroup)

RootView 继续执行 , 来到了 layout().
如果是一个简单的控件 , 那么 , 它的布局就是 (0,0,width,height) 它就可以把自己绘制出来了 ~ 但是 , 如果是一个 ViewGroup 的话 , 他还要负责自己的子控件的绘制 .
layout() , 首先会判断大小是否发生了变化 , 如果发生了变化 , 那么就会调用 onLayout() 来进行重新布局 .onlayout() 是所有 ViewGroup 必须复写的一个函数 ~ 只要为调用每一个子视图的 layout() 确定布局即可 ~

OnDraw()(自定义ViewGroup一般不需要管)

大小也知道了 , 位置也知道了 , 那么是时候去绘制自己啦 .
RootView 创建了一个 canvas, 其大小和位置由之前的结果所决定 , 然后调用了 draw().
draw() 做了以下几件事
1.画背景  2. 为绘制渐变框做准备  3. 调用 onDraw() 4. 子控件 draw() 5. 绘制滚动条
作为一个自定义 View, 我们的重点在 onDraw(), 在这里面传进来了 RootView 创建的
Canvas, 我们通过它 , 就可以自由自在的绘制我们想要的东西啦 ~~
Tip: 自定义 ViewGroup 可以通过重写 dispatchDraw() 来绘制前景 ~
Tip:ViewGroup 需要在构造函数中调用 setWillNotDraw(false),onDraw() 中的代码才会执行 .
 
requsetLayout() & invalidate()
requestLayout() 会导致重新测量 , 布局 , 以及重绘 ,invalidate() 导致重绘 , touchEvent 结合起来 , 可以搞出各种动画效果 ~
 

总结一下:自定义View主要重写onMeasure() onDraw();自定义ViewGroup则是onMesure()onLayout(),并且调用子控件的draw()以及layout()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值