UI 绘制流程(测量、布局、绘制)

UI 绘制流程(测量、布局、绘制)

View = 模式 + 尺寸 -> MeasureSpec 32位 int 值

00,0000000000,0000000000,0000000000


MODE_MASK:11,0000000000,0000000000,0000000000

~MODE_MASK:00,1111111111,1111111111,1111111111


SpecMode(前2位) + SpecSize(后30位)

public static final int UNSPECIFED = 0 << MODE_SHIFT; // 00,0000000000,0000000000,0000000000

父容器不对 View 做任何限制,系统内部使用


public static final int EXACTLY = 0 << MODE_SHIFT; // 01,0000000000,0000000000,0000000000

父容器检测出 View 的大小,View 的大小就是 SpecSize:LayoutParams -> match_parent or 固定大小


public static final int AT_MOST = 0 << MODE_SHIFT; // 10,0000000000,0000000000,0000000000

父容器指定一个可用大小,View 的大小不能超过这个值,LayoutParams -> wrap_content


mode + size -> MeasureSpec

MeasureSpec = mode + size


ViewGroup:measure -> onMeasure(测量子控件的宽高) -> setMeasureDimension -> setMeasureDimensionRaw(保存自己的宽高)

View:measure -> onMeasure -> setMeasureDimension -> setMeasureDimensionRaw(保存自己的宽高)

View 的测量-确定 DecorView 的 MeasureSpec

DecorView 的 MeasureSpec 由窗口大小和自身 LayoutParams 决定,遵守如下规则:

  • LayoutParams.MATCH_PARENT:精确模式,窗口大小
  • LayoutParams.WRAP_CONTENT:最大模式,最大为窗口大小
  • 固定大小:精确模式,大小为 LayoutParams 的大小

View 的 MeasureSpec 由父容器的 MeasureSpec 和自身 LayoutParams 决定

childLayoutParams\parentSpecMode EXACTLY AT_MOST UNSPECIFED
dp/px EXACTLY
childSize
EXACTLY
childSize
EXACTLY
childSize
match_parent EXACTLY
parentSize
EXACTLY
parentSize
UNSPECIFED
0
wrap_content AT_MOST
parentSize
AT_MOST
parentSize
UNSPECIFED
0

View 的布局

  • 调用 View.layout 确定自身的位置,即确定 mLeft,mTop,mRight,mBottom 的值。
  • 如果是 ViewGroup 类型,需要调用 onLayout 确定子 View 的位置。

ViewGroup:layout(来确定自己的位置,4个点的位置) -> onLayout(进行子 View 的布局)

View:layout(来确定自己的位置,4个点的位置)

View 的绘制

  • 绘制背景 drawBackground(canvas)
  • 绘制自己 onDraw(canvas)
  • 绘制子 View dispatchDraw(canvas)
  • 绘制前景,滚动条等装饰 onDrawForground(canvas)

自定义 View 的流程

onMeasure -> onLayout(容器) -> onDraw(可选)


UI 绘制流程(测量、布局、绘制)
https://blog.funkt.cn/2022/02/10/1491683021944815618/
作者
anjiemo
发布于
2022年2月10日
许可协议
未经作者授权,禁止转载