1. ViewRoot 的概念
ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和 DecorView 的纽带,View 的三大流程均是通过 ViewRoot 来完成的
在 ActivityThread 中,当 Activity 对象被创建完毕后,会将 DecorView 添加到 Window 中,同时会创建 ViewRootImpl 对象,并将 ViewRootImpl 对象和 DecorView 建立关联。源码如下:
1
2root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);
2. View 大致的绘制流程
View 的绘制流程是从 ViewRoot 的
performTraversal()
方法开始的,经过 measure、layout 和 draw 三个过程最终将一个 View 绘制出来- measure: 用来测量 View 的宽高
- layout: 用来确定 View 在父容器中的布局位置
- draw: 用来将 View 绘制在屏幕上
ViewRoot 的
performTraversal()
方法的工作流程图performTraversals()
会依次调用performMeasure()
、performLayout()
和performdraw()
三个方法,这三个方法分别完成顶级 View 的 measure、layout 和 draw 三大流程- 在
performMeasure()
中会调用 measure 方法,在 measure 方法中又会调用 onMeasure 方法,在 onMeasure 方法则会对所有的子元素进行 measure 过程。接着子元素会重复父容器的 measure 过程,如此反复就完成了整个 View 树的遍历 - 同理,
performLayout()
和performDraw()
的传递流程和performMeasure()
是类似的,唯一不同的是,performDraw()
的传递过程是在 draw 方法中通过dispatchDraw()
来实现的,不过这并没有本质区别
3. View 三大流程的具体含义
measure:
- measure 过程决定了 View 的宽高
- measure 完成以后,可以通过
getMeasuredWidth()
方法和getMeasuredHeight()
方法获取 View 测量后的宽高。在几乎所有的情况下它都等同于 View 最终的宽高,但是特殊情况除外
layout:
- layout 过程决定了 View 的四个顶点的坐标和实际的 View 的宽高
- layout 完成以后,可以通过
getTop()
、getBottom()
、getLeft()
和getRight()
四个方法来拿到 View 的四个顶点的坐标,并可以通过getWidth()
和getHeight()
方法来拿到 View 的最终宽高
draw:
- draw 过程决定了 View 的显示
- 只有 draw 方法完成以后 View 的内容才能呈现在屏幕上
4. DecorView 的概念
DecorView 作为顶级 View,一般情况下它内部会包含一个竖直方向的 LinearLayout,在这个 LinearLayout 里面有上下两个部分(具体情况和 Android 版本以及主题有关),上面时标题栏,下面是内容栏
- 得到 content:
ViewGroup content = (ViewGroup)findViewById(R.android.id.content);
- 得到 content 中设置的 View:
content.getChildAt(0);
- 得到 content:
分析源码可知,DecorView 其实是一个 FrameLayout,View 层的事件都先经过 DecorView,然后才传递给 View
作为顶级 View 的 DecorView 的结构示意图