View绘制机制
View的绘制机制
1. view树的绘制流程
(当Activity接收到用户触摸焦点的时候, 会被请求去绘制布局;请求是由安卓Framework层去处理绘制,从根节点去对布局进行测量和绘制ViewRoot类中)
measure -> layout -> draw
measure: 是否重新计算视图大小;
(递归)view 会对所有子元素进行测量, 测量过程从父的ViewGroup传递到子View里面, 经过子元素的递归, 测量好所有子元素的长度, 再进行递归, 反复之后就完成了ViewGroup的测量;
layout: 是否需要重新安置视图位置;
draw: 是否需要重绘;
2. measure
2.1 ViewGroup.LayoutParams:
用来指定视图的高度和宽度
2.2 MeasureSpec(测量规格):
32位int值 , 最高两位表示SpecMode是模式占位符, 后面30位表示测量规格的大小;
在一个空间measure过程中, 会将这个View的LayoutParams结合父容器生成一个MeasureSpec, MeasureSpec就会规定好怎样去测量这个View容器的大小, 返回给父容器, 父容器根据这个去测量大小
模式名称 | 模式数值 | 实际数值 |
---|---|---|
UNSPECIFIED | 00 | 000000000000000000001111011000 |
EXACTLY | 01 | 000000000000000000001111011000 |
AT_MOST | 10 | 000000000000000000001111011000 |
UNSPECIFIED: 不确定, 父控件不会对子控件有任何约束, 只要小于手机屏幕宽和高;
EXACTLY: 父容器会对子视图确定一个大小, 无论子视图有多大, 都必须限定在父容器给定的范围内;
AT_MOST : 父容器为所有子视图指定一个最大的尺寸, 子视图所有的大小都必须在这个范围内;
2.3 measure 重要的回调方法:
measure(): 调用onMeasure();
树遍历所有子结点;
onMeasure(): 将所有测量的规格传递给setMeasuredDimension();
1 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
setMeasuredDimension(): 完成整个测测量过程;
1 | /** |
注: 如果父视图发现子视图传递的大小可能不对时候, 会再次请求子视图进行测量, 如果给定的数值超过了规定大小或者太小, 父视图会赋值给AT_MOST 或者 EXACTLY的形式,再次对子视图进行测量
3. layout
会根据测量所得到的尺寸来确定layout摆放的位置, 子视图的具体位置是相对于父视图而言的, 必须实现onLayout(), 重新摆放;
layout(): 调用onLayout();
onLayout(): 一定要实现;
可以去分析LinearLayout中的实现;
1 | /** |
是一个树形结构, 依次从ViewGroup进行位置摆放
4. draw
两个比较容易混淆的回调方法:
4.1 invalidate(): 请求安卓系统;
如果视图大小没有发生变化, 则不会调用layout放置过程;
4.2 requestLayout(): 当布局方向变化, 尺寸变化就回去调用;
会触发measure, layout过程, 但不会调用draw方法