View添加到窗口过程
当我们调用 setContentView(R.layout.activity_main); 这行代码时
- 会调用Window的setContentView方法,Window是个抽象类,而它唯一的子类就是PhoneWindow。所以实际上调用的是PhoneWindow中的setContentView方法。
- PhoneWindow中setContentView方法中调用了 installDecor 方法,初始化了DecorView。DecorView是一个继承了FrameLayout的容器。在这个初始化的方法中,通过不同的条件加载了一个系统的布局到DecorView上。
- 通过下面这行代码创建出一个容器,这个容器被添加到上面说到的系统布局里。随后又将我们调用setContentView(R.layout.activity_main)中的布局添加到这个容器里。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); mLayoutInflater.inflate(layoutResID, mContentParent); 复制代码
这样就完成了将我们设置的布局添加到窗口的全过程。
View的绘制过程
View的绘制过程稍微比添加过程复杂些,但是可以从源码中一点点分析中。
1.在ActivityThread类里handleResumeActivity方法中,有一段关键代码,通过ViewManager调用addView方法,ViewManager是个接口,它的子类是WindowManagerImpl,也就是会调用这里面的addView方法。
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);}复制代码
2.在WindowManagerImpl里调用addView方法,实际上是调用了WindowManagerGlobal的addView方法,在这个方法中,有这样一段代码,
root.setView(view, wparams, panelParentView);复制代码
这个root就是ViewRootImpl,连接了View和WindowManager。
3.通过调用上面的setView方法,将DecorView绘制到了窗口上,接下来进入requestLayout方法,开始通过线程进行performMeasure,performLayout,performDraw方法,即测量,布局,绘制。
ViewGroup和View的测量过程
MeasureSpec的概念,可以理解成封装了size和mode的类。
UNSPECIFIED,EXACTLY,AT_MOST这是类中的几个值,稍后在测量中我们会用到它们。
UNSPECIFIED一般是系统控件,用的较少。
EXACTLY精确模式。
AT_MOST最大模式。
复制代码
- ViewGroup的测量过程
以DecorView为例,它是继承FrameLayout的容器。那么它测量的过程是这样的:
measure方法中调用onMeasure,即Framelayout中的onMeasure方法。通过看源码得知这个方法首先去遍历了所有的子View,通过getChildMeasureSpec这个方法来确定子View的MeasureSpec。规则如下:
父类EXACTLY模式
子类:
LayoutParams.MATCH_PARENT,则size是父布局的size,mode为EXACTLY精确模式。
LayoutParams.WRAP_CONTENT,则size是父布局的size,mode为AT_MOST最大模式。
其它固定值的情况,size就是子View设置的值,比如给TextView设置100dp,那么这个size就是100dp,mode为EXACTLY精确模式。
父类AT_MOST模式
子类:
LayoutParams.MATCH_PARENT,则size是父布局的size,mode为AT_MOST最大模式。
LayoutParams.WRAP_CONTENT,则size是父布局的size,mode为AT_MOST最大模式。
其它固定值的情况,size就是子View设置的值,mode为EXACTLY精确模式。
通过以上的测量,可以得到一个ViewGroup的最大宽高,接着调用setMeasuredDimension方法和setMeasuredDimensionRaw方法完成测量。
- View的测量过程
View的测量过程和ViewGroup类似,只省略了测量遍历子View的过程。需要注意的是,在View的setMeasuredDimension方法里,View的size无论在什么情况下都被赋值为父控件的剩余空间,所以自定义View时需要重写onMeasure方法。
以上就是ViewGroup和View的测量过程。
View的布局过程
View的布局过程比较简单,就是通过调用View的layout方法,通过测量的值来确定View的上下左右四个点的值。需要注意的是如果是自定义ViewGroup需要实现onLayout方法来确定子View的摆放位置,如果是自定义View则不需要。
View的绘制过程
View的绘制过程比较简单,和layout方法差不多,ViewGroup需要绘制子View,而View则只需要调用draw方法即可。