<强>前言强>
上一篇文章,笔者主要讲述了DecorView以及ViewRootImpl相关的作用,这里回顾一下上一章所说的内容:DecorView是视图的顶级视图,我们添加的布局文件是它的一个子布的局,而ViewRootImpl则负责渲染视图,它调用了一个performTraveals方法使得ViewTree开始三大工作流程,然后使得观点展现在我们面前。本篇文章主要内容是:详细讲述视图的测量(测量)流程,主要以源码的形式呈现,源码均取自Android API 21。
<强>从ViewRootImpl # PerformTraveals说起强>
我们直接从这个方法说起,因为它是整个工作流程的核心,我们看看它的源码:
私人空间performTraversals () { … 如果(! mStopped) { int childWidthMeasureSpec=getRootMeasureSpec (mWidth lp.width);//1 int childHeightMeasureSpec=getRootMeasureSpec (mHeight lp.height); performMeasure (childWidthMeasureSpec childHeightMeasureSpec); } } 如果(didLayout) { performLayout (lp desiredWindowWidth desiredWindowHeight); … } 如果(!cancelDraw,,! newSurface) { 如果(!skipDraw | | mReportNextDraw) { 如果(mPendingTransitions !=零,,mPendingTransitions.size()比;0){ for (int i=0;我& lt;mPendingTransitions.size ();+ + i) { mPendingTransitions.get (i) .startChangingAnimations (); } mPendingTransitions.clear (); } performDraw (); } } … } >之前方法非常长,这里做了精简,我们看到它里面主要执行了三个方法,分别是performMeasure, performLayout, performDraw这三个方法,在这三个方法内部又会分别调用测量、布局,画这三个方法来进行不同的流程。我们先来看看performMeasure (childWidthMeasureSpec childHeightMeasureSpec)这个方法,它传入两个参数,分别是childWidthMeasureSpec和childHeightMeasure,那么这两个参数代表什么意思呢?要想了解这两个参数的意思,我们就要先了解MeasureSpec。
<强>理解MeasureSpec 强>
MeasureSpec是视图类的一个内部类,我们先看看官方文档对MeasureSpec类的描述:MeasureSpec封装了布局要求从父母传给孩子。每个MeasureSpec代表一个宽度或高度要求。MeasureSpec由大小和一个模式。它的意思就是说,该类封装了一个视图的规格尺寸,包括视图的宽和高的信息,但是要注意,MeasureSpec并不是指视图的测量宽高,这是不同的,是根据MeasueSpec而测出测量宽高。
MeasureSpec的作用在于:在测量流程中,系统会将视图的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,然后在onMeasure方法中根据这个MeasureSpec来确定视图的测量宽高。
我们来看看这个类的源码:公共静态类MeasureSpec { 私有静态最终int MODE_SHIFT=30; 私有静态最终int MODE_MASK=0 x3 & lt; & lt;MODE_SHIFT;/* * *未指明的模式: *父视图不对子视图有任何限制,子视图需要多大就多大 */公共静态最终int不明=0 & lt; & lt;MODE_SHIFT;/* * * EXACTYLY模式: *父视图已经测量出子另外所需要的精确大小,这时候视图的最终大小 *就是SpecSize所指定的值。对应于match_parent和精确数值这两种模式 */公共静态最终int=1 & lt; & lt;MODE_SHIFT;/* * * AT_MOST模式: *子视图的最终大小是指父视图定的SpecSize值,并且子视图的大小不能大于这个值, *即对应wrap_content这种模式 */公共静态最终int AT_MOST=2 & lt; & lt;MODE_SHIFT;//将规模和模式打包成一个32位的整数型数的值//高2位表示SpecMode,测量模式,低30位表示SpecSize,某种测量模式下的规格大小 公共静态int makeMeasureSpec (int, int模式){ 如果(sUseBrokenMakeMeasureSpec) { 返回大小+模式; 其他}{ 返回(大小,~ MODE_MASK) |(模式,MODE_MASK); } }//将32位的MeasureSpec解包,返回SpecMode,测量模式 公共静态int getMode (int measureSpec) { 返回(measureSpec,MODE_MASK); }//将32位的MeasureSpec解包,返回SpecSize,某种测量模式下的规格大小 公共静态int getSize (int measureSpec) { 返回(measureSpec,~ MODE_MASK); }//? } >之前可以看的出,该类的思路是相当清晰的,对于每一个视图中,包括DecorView,都持有一个MeasureSpec,而该MeasureSpec则保存了该视图的尺寸规格。在视图的测量流程中,通过makeMeasureSpec来保存宽高信息,在其他流程通过getMode或getSize得到模式和宽高。那么问题来了,上面提到MeasureSpec是LayoutParams和父容器的模式所共同影响的,那么,对于DecorView来说,它已经是顶层视图了,没有父容器,那么它的MeasureSpec怎么来的呢?
Android视图测量流程(测量)全面解析