前言
安卓控件方法当中,measure用于宽高的测量,layout用于指定控件的位置, draw用于界面的渲染;不同层级的控件组成控件树,在界面生成的初始阶段是遍历树进行measure,然后是layout,最后是draw。已知的invalide()是用于View的界面强制重绘,即重新执行onDraw方法,那么另一个常见的requestLayout方法,一般解释是“
”,那么具体是如何工作的呢?
测试
测试逻辑:通过自定义View和ViewGroup并加入日志;任意点击事件中执行两者的requestLayout方法并观察
测试1:记录应用启动流程
日志:
:inflate、attached 06-29 11:14:03.065: I/MyView(17365): ->onFinishInflate 06-29 11:14:03.065: I/MyView(17365): <-onFinishInflate 06-29 11:14:03.065: I/MyLinearLayout(17365): ->onFinishInflate 06-29 11:14:03.065: I/MyLinearLayout(17365): <-onFinishInflate 06-29 11:14:03.085: I/MyLinearLayout(17365): ->onAttachedToWindow 06-29 11:14:03.085: I/MyLinearLayout(17365): <-onAttachedToWindow 06-29 11:14:03.085: I/MyView(17365): ->onAttachedToWindow 06-29 11:14:03.085: I/MyView(17365): <-onAttachedToWindow :measure、layout 06-29 11:14:03.085: I/MyLinearLayout(17365): ->onMeasure 06-29 11:14:03.085: I/MyLinearLayout(17365): ->measureChildWithMargins 06-29 11:14:03.085: I/MyView(17365): ->onMeasure 06-29 11:14:03.085: I/MyView(17365): <-onMeasure 06-29 11:14:03.085: I/MyLinearLayout(17365): <-measureChildWithMargins 06-29 11:14:03.085: I/MyLinearLayout(17365): <-onMeasure 06-29 11:14:03.085: I/MyLinearLayout(17365): ->onMeasure 06-29 11:14:03.085: I/MyLinearLayout(17365): ->measureChildWithMargins 06-29 11:14:03.085: I/MyView(17365): ->onMeasure 06-29 11:14:03.085: I/MyView(17365): <-onMeasure 06-29 11:14:03.085: I/MyLinearLayout(17365): <-measureChildWithMargins 06-29 11:14:03.085: I/MyLinearLayout(17365): <-onMeasure 06-29 11:14:03.105: I/MyLinearLayout(17365): ->onLayout 06-29 11:14:03.105: I/MyView(17365): ->layout 06-29 11:14:03.105: I/MyView(17365): ->onLayout 06-29 11:14:03.105: I/MyView(17365): <-onLayout 06-29 11:14:03.105: I/MyView(17365): <-layout 06-29 11:14:03.105: I/MyLinearLayout(17365): <-onLayout :measure、layout 06-29 11:14:03.115: I/MyLinearLayout(17365): ->onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): ->measureChildWithMargins 06-29 11:14:03.115: I/MyView(17365): ->onMeasure 06-29 11:14:03.115: I/MyView(17365): <-onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): <-measureChildWithMargins 06-29 11:14:03.115: I/MyLinearLayout(17365): <-onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): ->onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): ->measureChildWithMargins 06-29 11:14:03.115: I/MyView(17365): ->onMeasure 06-29 11:14:03.115: I/MyView(17365): <-onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): <-measureChildWithMargins 06-29 11:14:03.115: I/MyLinearLayout(17365): <-onMeasure 06-29 11:14:03.115: I/MyLinearLayout(17365): ->onLayout 06-29 11:14:03.115: I/MyView(17365): ->layout 06-29 11:14:03.115: I/MyView(17365): ->onLayout 06-29 11:14:03.115: I/MyView(17365): <-onLayout 06-29 11:14:03.115: I/MyView(17365): <-layout 06-29 11:14:03.115: I/MyLinearLayout(17365): <-onLayout :draw 06-29 11:14:03.125: I/MyLinearLayout(17365): ->onDraw 06-29 11:14:03.125: I/MyLinearLayout(17365): <-onDraw 06-29 11:14:03.125: I/MyView(17365): ->onDraw 06-29 11:14:03.125: I/MyView(17365): <-onDraw
测试2:测试执行view.requestLayout
日志:
06-29 11:06:51.905: I/MyLinearLayout(15565): ->onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): ->measureChildWithMargins 06-29 11:06:51.905: I/MyView(15565): ->onMeasure 06-29 11:06:51.905: I/MyView(15565): <-onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): <-measureChildWithMargins 06-29 11:06:51.905: I/MyLinearLayout(15565): <-onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): ->onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): ->measureChildWithMargins 06-29 11:06:51.905: I/MyView(15565): ->onMeasure 06-29 11:06:51.905: I/MyView(15565): <-onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): <-measureChildWithMargins 06-29 11:06:51.905: I/MyLinearLayout(15565): <-onMeasure 06-29 11:06:51.905: I/MyLinearLayout(15565): ->onLayout (注:MyLinearLayout.layout为final方法,无法重写,所以此处应缺少其layout日志) 06-29 11:06:51.905: I/MyView(15565): ->layout 06-29 11:06:51.905: I/MyView(15565): ->onLayout 06-29 11:06:51.905: I/MyView(15565): <-onLayout 06-29 11:06:51.905: I/MyView(15565): <-layout 06-29 11:06:51.905: I/MyLinearLayout(15565): <-onLayout
测试3:设置view动态高度,如下:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.i(TAG, "->onMeasure"); int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); int measuredHeight = 50 * ++time; setMeasuredDimension(measuredWidth, measuredHeight); Log.i(TAG, "<-onMeasure"); }
,测试其requestLayout
日志:
06-29 11:02:31.785: I/MyLinearLayout(15016): ->onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): ->measureChildWithMargins 06-29 11:02:31.785: I/MyView(15016): ->onMeasure 06-29 11:02:31.785: I/MyView(15016): <-onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): <-measureChildWithMargins 06-29 11:02:31.785: I/MyLinearLayout(15016): <-onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): ->onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): ->measureChildWithMargins 06-29 11:02:31.785: I/MyView(15016): ->onMeasure 06-29 11:02:31.785: I/MyView(15016): <-onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): <-measureChildWithMargins 06-29 11:02:31.785: I/MyLinearLayout(15016): <-onMeasure 06-29 11:02:31.785: I/MyLinearLayout(15016): ->onLayout 06-29 11:02:31.785: I/MyView(15016): ->layout 06-29 11:02:31.785: I/MyView(15016): ->onLayout 06-29 11:02:31.785: I/MyView(15016): <-onLayout 06-29 11:02:31.785: I/MyView(15016): <-layout 06-29 11:02:31.785: I/MyLinearLayout(15016): <-onLayout :相比2,多处以下部分 06-29 11:02:31.785: I/MyLinearLayout(15016): ->onDraw 06-29 11:02:31.785: I/MyLinearLayout(15016): <-onDraw 06-29 11:02:31.795: I/MyView(15016): ->onDraw 06-29 11:02:31.795: I/MyView(15016): <-onDraw 06-29 11:02:31.805: I/MyLinearLayout(15016): ->onDraw 06-29 11:02:31.805: I/MyLinearLayout(15016): <-onDraw 06-29 11:02:31.805: I/MyView(15016): ->onDraw 06-29 11:02:31.805: I/MyView(15016): <-onDraw
测试3:执行group.requestLayout
日志:
06-29 11:00:39.295: I/MyLinearLayout(14655): ->onMeasure 06-29 11:00:39.295: I/MyLinearLayout(14655): ->measureChildWithMargins 06-29 11:00:39.295: I/MyLinearLayout(14655): <-measureChildWithMargins 06-29 11:00:39.295: I/MyLinearLayout(14655): <-onMeasure 06-29 11:00:39.295: I/MyLinearLayout(14655): ->onMeasure 06-29 11:00:39.295: I/MyLinearLayout(14655): ->measureChildWithMargins 06-29 11:00:39.295: I/MyLinearLayout(14655): <-measureChildWithMargins 06-29 11:00:39.295: I/MyLinearLayout(14655): <-onMeasure 06-29 11:00:39.295: I/MyLinearLayout(14655): ->onLayout 06-29 11:00:39.295: I/MyView(14655): ->layout 06-29 11:00:39.295: I/MyView(14655): <-layout 06-29 11:00:39.295: I/MyLinearLayout(14655): <-onLayout
测试4:执行group.getParent().requestLayout
日志:同上
总结
拷贝转帖中的主要内容如下:
当一个View调用requestLayout的时候,会给当前的View设置一个FORCE_LAYOUT标记。由此向ViewParent请求布局。这样从这个View开始向上一直requestLayout。最终到达ViewRootImpl。ViewParent 就是当前的传输链。【参见职责链设计模式】
第一步。
ViewRootImpl发现请求了布局。那么就会调用measure方法。
measure方法确认当前View是否有FORCE_LAYOUT标记。
如果有,那么就会进行重新measure。并且设置标记LAYOUT_REQUIRED。
第二步。
在随后的layout方法中,会判断这个标记。如果这个标记为true。
那么就一定会调用onLayout.
onLayout调用后清理LAYOUT_REQUIRED标记。
layout调用之后,会清理掉FORCE_LAYOUT标记。
综合测试和网友,简单整理如下:
1、requestLayout会为view添加FORCE_LAYOUT并逐级传递事件至根控件,之后再自上而下measure、layout
2、在必要的时候会触发执行draw事件,如宽高和位置的改变
3、对ViewGroup等中间层控件执行requestLayout,并不会导致其子控件onMeasure被调用,但onLayout会有