4.1View相关-View绘制详解

View的绘制机制

    1. view树的绘制流程
    1. measure方法
    1. layout方法
    1. draw方法

1.view树的绘制流程

    1. 当Activity接收到用户的触摸焦点后,就会被请求去绘制布局。
    1. 请求是android的framework层处理绘制的,从根节点开始测量和绘制。整个View树的绘制流程是在ViewRoot类中有一个叫FrameWorkTran 函数中,这个函数工作:
        1. 是否重新计算视图大小(measure)
        1. 是否需要重新安置视图位置(layout)
        1. 是否需要重绘(draw)
    1. 总结:measure->layout->draw
      1. View树的绘制流程就像一个递归过程。
      1. 在measure方法里,会对所有它的子元素进行测量,然后测量过程从父的Group传到子View里面,反复
      1. 在layout中也是

2.measure方法


measure是树的递归过程,从上往下有序的进行遍历

    1. DecorView
    1. ViewGroup
    1. ViewGroup View View
    1. View View

    它会根据父容器对子容器的测量规格参数,获取到子容器的长宽高,把子容器的长宽高返还给父容器进行统一的测量,它是树的遍历过程,从上到下进行遍历

重要参数:

    1. ViewGroup.LayoutParams 设置具体值 设置wrap (不包括padding值)
    1. MeasureSepc int值,
    • 最高的两位SpecMode是模式占位符,后面的30位是这种测量模式下的尺寸大小
    • 模式:不确定(基本不用)。精确的(exactly),自适应(as_most ---wrap-content)

总结:

  • LayoutParams最终也会被封装成MeasureSpec。
  • MeasureSpec作用就是在measure的过程中系统会将View的LayoutParams 根据父容器所施加的mode规则转换成对应的MeasureSpec。然后会在测量的方法当中onMeasure根据这个测量规则去确定View的长宽高

measure 三个重要的方法

    1. measure方法 final。在java中
      最后还是调用到了onMeasure方法。自定义时复写onMeasure方法
    1. onMeasure 。在自定义中需要实现测量逻辑的方法
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
        setMeasuredDimension(getDefaultSize(getSuggestedMiniumWidth(),widthMeasureSpec),xxx同理)
}
    1. setMeasuredDimension 这个方法是测量阶段的终极,确定大小
      • 这个方法说明:我们会将 在measure方法里面获得的计算尺寸传给setMeasuredDimension方法。这是一个测量阶段结束的方法,必须要调用,完成整个的测量过程,

      • 串联:measure是根据树遍历的,measure过程会为每一个View和所有子节点的宽高赋值,该值通过一个get方法可以获取到,但是要注意,这两个宽高必须要在父视图的约束范围内,父视图通过测量规格MeasureSpec来约束,这样才能保证所有父视图能够接受子视图给他传递的测量。

      • android有这样一个机制:如果父视图发现给他传递的子视图的宽高 有觉得不对的地方,它会再次请求子视图去进行测量,第二次measure,父视图可以根据未给定的Dimension去测量每一个视图,如果最终的子视图太小或者超过了父视图约束,父视图就会给他设置一个确切的大小,设置成as_most或者exactly形式再次给子视图测量的过程。

总结:

  • measure开始于父控件ViewGroup,通过不断的遍历子控件的measure方法,

  • 然后根据ViewGroup的MeasureSpec 和子控件的LayoutParams来决定子视图的MeasureSpec测量规格,通过这个测量规格来进一步获取到子View的测量的宽高,

  • 然后一层一层的向下传递,不断的保存整个父控件的测量宽高。

  • 整个测量调用流程就是一个树形的递归过程,为整个View树计算实际的大小。每一个View视图的实际的宽和高都是由父视图和它本身LayoutParams决定的。

    最复杂 最重要的流程。MeasureSpec

3.layout方法

layout方法会根据测量所得到尺寸来摆放子视图的位置,首先明确的是:子视图的位置是相对于父视图而言的,View的onLayout方法是空实现,如果要自定义View的时候,继承ViewGroup,必须要实现onLayout方法,然后重新来摆放自己想要自定义View的位置。
onLayout方法 。抽象的

protected abstract void onLayout(boolean changed,int l,int t,int r,int b);

看一个实例:LinearLayout他的onLayout。图:

举例:layoutVertical()

    遍历子视图:
        获取子View的测量宽高。child。getMeasureedWidth();
    然后
        final LinerLayout.LayoutParams lp = (xx)child.getLayoutParams();
        这是child 父容器的测量规格
                
    然后
        childTop +=lp.topMargin;
    最终
        setChildFrame(child,childLeft,childTop+getLocationOffset(child),childWidth,childHeight);
        childTop +=childHeight +lp.bottomMargin +getNextLocationOffset(child);
        i += getChildrenSkipCount(child,i); 
        setChildFrame根据长宽高和位置绘制

总结:
layout也是一个树形的结构,它进性位置摆放的时候,会依次的从ViewGroup调用它的子控件进性位置的摆放

4.draw方法

draw-两个容易混淆的方法

    1. invalidate
      --请求系统的绘制方法,如果这时的视图大小没有发生变化,就不会调用layout放置这个过程
    1. requestLayout()
      当布局发生变化的时候,比如说方向变化,尺寸变化,我们就会调用requestLayout方法,他会自动的出发measure和layout方法,但是不会调用draw方法。

回顾:

  • 当Activity接收到用户触摸的时候,它会请求绘制布局,这个请求是由android的framework来处理的
  • 它的处理方式是从根节点开始对布局进行测量和绘制,而整个的View的绘制流程都是通过measure,layout,draw三个方法来实现的。
  • 它们三个的意义分别是,是否需要重新计算视图大小,是否需要重新安置视图位置,测量好放置好 是否需要重绘。
    这是View树的绘制流程

你可能感兴趣的:(4.1View相关-View绘制详解)