View学习之旅

View添加到窗口过程

当我们调用  setContentView(R.layout.activity_main); 这行代码时

  1. 会调用Window的setContentView方法,Window是个抽象类,而它唯一的子类就是PhoneWindow。所以实际上调用的是PhoneWindow中的setContentView方法。
  2. PhoneWindow中setContentView方法中调用了 installDecor 方法,初始化了DecorView。DecorView是一个继承了FrameLayout的容器。在这个初始化的方法中,通过不同的条件加载了一个系统的布局到DecorView上。
  3. 通过下面这行代码创建出一个容器,这个容器被添加到上面说到的系统布局里。随后又将我们调用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方法即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值