View绘制流程简介

简单梳理一下View的绘制流程。View的绘制分为三个部分(mechanism),分别为:measure,layout,draw。


第一部分:Measure

这一过程负责确定各个View的大小,得到的结果存放在每个ViewmMeasuredWidthmMeasuredHeight中。

该部分主要有三个函数:

measure(int widthMeasureSpec, int heightMeasureSpec);
onMeasure(int widthMeasureSpec, int heightMeasureSpec);
setMeasuredDimension(int measuredWidth, int measuredHeight);

measure(int, int)

发起measure过程,需要用到两类信息:

  1. MeasureSpecs,父View对子View的要求,有三种模式:UNSPECIFIEDEXACTLYAT_MOST
  2. ViewGroup.LayoutParams,子View自身的布局参数,可以是具体值、MATCH_PARENTWRAP_CONTENT

该方法为final方法,不可被Override,该方法会调用onMeasure(),一般情况下子类应该Override onMeasure()方法。

onMeasure(int, int)

进行具体的测量工作,该函数的参数是mMeasuredWidthmMeasuredHeight,即父View对我们的测量要求,要做的工作就是根据父View的大小确定自己的大小。如果是ViewGroup,还要调用子Viewmeasure(int, int)才能确定自己的大小。同时这一步的最后需要调用setMeasuredDimension(int, int)将测量结果存储起来,否则在使用过程中会抛出异常。

setMeasuredDimension(int, int)

将测量结果存储在mMeasuredWidthmMeasuredHeight中,在之后的步骤中,可以通过getMeasuredWidth()getMeasuredHeight()获取这两个参数。


第二部分:Layout

这一部分通过Measure中得到的各个View的大小,确定各个View的摆放位置。

该部分主要有两个函数:

layout(int l, int t, int r, int b);
onLayout(boolean changed, int l, int t, int r, int b);

相对于measure,这部分比较简单,最后会通过setFrame(int, int, int, int)确定各个View相对于父View的座标。

第三部分:Draw

该部分绘制View的内容。

主要有两个函数:

draw(Canvas canvas);
onDraw(Canva canvas);

draw(Canvas)

代码略长,但主要工作是调用onDraw()绘制自己,然后调用dispatchDraw()绘制子View

根据文档说明,该方法负责渲染将View以及所有子View渲染到Canvas,必须在layout完成后调用,一般不应该Override该方法,如果要继承,可以Override onDraw()方法。

也就是说自定义View的时候基本可以不考虑这个方法。

onDraw(Canvas)

ViewonDraw()方法为空实现,subclass一般要Override该方法,绘制自己。

比如,想绘制一个矩形:

// 画一个起点座标(0,0),终点座标(10,20)的矩形
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, 10, 20, paint);

dispatchDraw(Canvas)

调用子Viewdraw()方法,绘制子View

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章