View绘制流程
此文章为自己的一个笔记。
一.onCreate()
从Activity的生命周期来说,从onCreate()方法开始,那么,页面的布局应该从onCreate()方法里的setContentVIewI()说起。
-
setContentVIew()源码如下:
public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
- 调用当前Window的
setContentView
方法。 initWindowDecorActionBar()
- 调用当前Window的
-
Window的
setContentView()
源码如下:@Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { mLayoutInflater.inflate(layoutResID, mContentParent); } final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
-
installDecor()
创建了DecorView。- 同时解析了对该Activity做的一些显示配置:如:是否浮动、是否支持状态栏、全屏、颜色、过场动画等。
- DecorView默认inflate了一个布局,包含actionBar和contentView。
-
由此我们可以得出:
image
-
LayoutInflater.inflate()
用来加载xml布局。- 方法内会先遍历拿到根节点
- 若根节点不是
<merge>
,创建一个rootView,若是则不再创建,直接使用现有的root布局(父布局)。 - 将该布局的子View加载到rootView/root下。
-
二.onResume()
View真正的绘制,是从onResume()开始。
-
从ActivityThread的
handleResumeActivity()
方法开始,会调用到WindowManageImpl的addView()
方法,最后调用ViewRootImpl的performTraversals()
方法,进入View的绘制。 -
在
performTraversals()
方法内,会拿到DecorView,然后依次执行测量(Measure)、布局(Layout)、绘制(draw)-
在执行
Measure()
方法前,会先通过测量模式和测量大小,得出子View的WidthMeasureSpec
和HeightMeasureSpec
,然后作为参数传入测量方法,该方法不可重写,只能重写该方法下的onMeasure()
方法。三个测量模式如下:-
UNSPECIFIED
未指定模式,View想多大就多大,通常在绘制自定义View时才会用,不常用。
-
AT_MOST
最大值模式,当空间的宽高设置为wrap_content时。
-
EXACTLY
精确值模式,当控件的layout_width和layout_height属性指定为具体数值或match_parent时。
-
这里需要注意一点,自定义控件时,AT_MOST和EXACTLY返回的尺寸均为父容器的大小,所以需要自己实现。
-
-
对于View来说,在
layout()
方法下会确定自己的位置(mLeft,mRight,mTop,mBottom四个值),而对于ViewGroup来说,在确定自己的位置之后,还需调用onLayout()
方法来给子View确定位置。- 自定义ViewGroup时,必须实现
onLayout()
方法,而View则不必。 - 在ViewGroup内实现
onLayout()
方法时,由于已经确定自己的位置,所以可以直接调用getHeight()
和getWidth()
。 - 这里有一个回调方法叫
OnLayoutChangeListener()
,用来监听View的位置变化,通过addOnLayoutChangeListener()
方法添加。
- 自定义ViewGroup时,必须实现
-
View的绘制是通过
draw()
方法实现的,一般遵循以下几个步骤:- 绘制背景 -- drawBackground()
- 绘制自己 -- onDraw()
- 绘制孩子 -- dispatchDraw()
- 绘制装饰 -- onDrawScrollbars()
-
网友评论