您的位置:首页 > 移动开发 > Android开发

Android View框架总结(四)View布局流程之Measure

2016-09-08 17:10 357 查看
转自http://blog.csdn.net/hejjunlin/article/details/52201637

View树的measure流程
View的measures时序图
View布局流程之measure 
measure过程 
View的measure过程
ViewGroup的measure过程
FrameLayout的measure过程


View树的measure流程图如下:




View树的measure时序图:




View的measure过程

View的measure方法如下:

View.Java 



这是个final方法, 子类不能重写, 主要是在里面会调用onMeasure方法.

此处有一个优化, 就是把MeasureSpec保存, 下次执行measure方法时如果measureSpec不变就不执行measure流程, 除非设置了PFLAG_FORCE_LAYOUT标志, 这个标志就是在requestLayout里面设置的. 

onMeasure之后会检查PFLAG_MEASURED_DIMENSION_SET标志, 也就是要求的onMeasure方法里面要调用setMeasuredDimensition方法(注意此方法设置的是尺寸不是MeasureSpec). 

看默认的onMeasure方法


 

这里调用 setMeasuredDimension方法,默认通过getDefaultSize计算宽高. 其中 在看此方法之前,先看getSuggestedMinimumxxx()方法:


 

getSuggestedMinimumWidth是此View的最小尺寸, 一般是背景图片的尺寸和minWidth/minHeight属性值较大的. 当然也可以重写此方法返回自定义值.

然后看getDefaultSize()方法: 


 

不限定大小则返回自己大小, 否则返回父容器限定的最大值. 

结合上面的MeasureSpec我们知道, 如果View的LayoutParams使用wrap_content, 那么它的SpecMode是AT_MOST模式. 这种情况下此View大小是父容器的剩余空间大小, 和match_parent一致了. 因此一般情况下自定义View的子类都需要重新onMeasure方法. 

再看setMeasuredDimension方法: 



这个方法决定了当前View的大小,也是一个final方法,写自定义控件大小时,重写onMeasure方法,最终都会调用此方法。到此一次最基础的元素View的measure过程就完成了。

View实际是挂在decorView树上的树枝,而且measure是递归的,所以每个View都需要measure。一般能够嵌套的View一般都是ViewGroup的子类,所以在ViewGroup中定义了measureChildren, measureChild, measureChildWithMargins方法来对子视图进行测量,measureChildren内部实质只是循环调用measureChild,measureChild和measureChildWithMargins的区别就是是否把margin和padding也作为子视图的大小。下面分析ViewGroup的measure过程


ViewGroup的measure过程

ViewGroup的measure过程除了完成自己的measure, 还需要遍历左右的子元素的measure方法. 虽然ViewGroup提供了measureChildren方法遍历每个子元素进行measure, 但是不同的布局类型有不同的measure逻辑, 有的ViewGroup自身尺寸依赖子元素的尺寸(如LinearLayout), 有的部分依赖子元素尺寸(如ScrollView), 因此需要子类实现onMeasure具体过程.

measureChildren方法: 



measureChild方法: 



measureChildWithMargins方法: 



虽然不同ViewGroup的measure流程不一致, 但是measure单个子View的逻辑基本是一样的, 就是上面的measureChildWidthMargins方法, 因此ViewGroup子类基本都使用此方法来measure子元素.

以上几个方法都会调用getChildMeasureSpec()方法: 



补充 MeasureSpec.makeMeasureSpec(resultSize, resultMode),也可以看上一篇 
Android View框架总结(三)View工作原理 


 

从这个逻辑,我们可以知道child的specMode,specSize是通过其父View提供的MeasureSpec参数得到specMode和specSize,然后根据计算出来的specMode以及子View的childDimension(layout_width或layout_height)来计算自身的measureSpec,如果其本身包含子视图,则计算出来的measureSpec将作为调用其子视图measure函数的参数,同时也作为自身调用setMeasuredDimension的参数,如果其不包含子视图则默认情况下最终会调用onMeasure的默认实现,并最终调用到setMeasuredDimension。


FrameLayout的measure过程


 


 

上面方法总结如下:
如果传入的SpecMode是EXACTLY, FrameLayout自身的尺寸不依赖子元素, 或者子元素是wrap_content(有AT_MOST限制), 那么一次遍历即可完成, 子元素兄弟之间没有依赖关系, 都是调用measureChildWidthMargins即可;
否则需要遍历子元素measure后, 取最大的尺寸(但不超过父容器限制)为自身尺寸, 然后重新measure那些宽或高是match_parent的子元素, 再次遍历过程中SpecMode变成了EXACTLY.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: