android 测量过程,Android View 测量流程(Measure)全面解析

前言

上一篇文章,笔者主要讲述了DecorView以及ViewRootImpl相关的作用,这里回顾一下上一章所说的内容:DecorView是视图的顶级View,我们添加的布局文件是它的一个子布局,而ViewRootImpl则负责渲染视图,它调用了一个performTraveals方法使得ViewTree开始三大工作流程,然后使得View展现在我们面前。本篇文章主要内容是:详细讲述View的测量(Measure)流程,主要以源码的形式呈现,源码均取自Android API 21.

从ViewRootImpl#PerformTraveals说起

我们直接从这个方法说起,因为它是整个工作流程的核心,我们看看它的源码:

private void performTraversals() {

...

if (!mStopped) {

int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); // 1

int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

}

}

if (didLayout) {

performLayout(lp, desiredWindowWidth, desiredWindowHeight);

...

}

if (!cancelDraw && !newSurface) {

if (!skipDraw || mReportNextDraw) {

if (mPendingTransitions != null && mPendingTransitions.size() > 0) {

for (int i = 0; i < mPendingTransitions.size(); ++i) {

mPendingTransitions.get(i).startChangingAnimations();

}

mPendingTransitions.clear();

}

performDraw();

}

}

...

}

方法非常长,这里做了精简,我们看到它里面主要执行了三个方法,分别是performMeasure、performLayout、performDraw这三个方法,在这三个方法内部又会分别调用measure、layout、draw这三个方法来进行不同的流程。我们先来看看performMeasure(childWidthMeasureSpec, childHeightMeasureSpec)这个方法,它传入两个参数,分别是childWidthMeasureSpec和childHeightMeasure,那么这两个参数代表什么意思呢?要想了解这两个参数的意思,我们就要先了解MeasureSpec。

理解MeasureSpec

MeasureSpec是View类的一个内部类,我们先看看官方文档对MeasureSpec类的描述:A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement for either the width or the height. A MeasureSpec is comprised of a size and a mode.它的意思就是说,该类封装了一个View的规格尺寸,包括View的宽和高的信息,但是要注意,MeasureSpec并不是指View的测量宽高,这是不同的,是根据MeasueSpec而测出测量宽高。

MeasureSpec的作用在于:在Measure流程中,系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,然后在onMeasure方法中根据这个MeasureSpec来确定View的测量宽高。

我们来看看这个类的源码:

public static class MeasureSpec {

private static final int MODE_SHIFT = 30;

private static final int MODE_MASK = 0x3 << MODE_SHIFT;

/**

* UNSPECIFIED 模式:

* 父View不对子View有任何限制,子View需要多大就多大

*/

public static final int UNSPECIFIED = 0 << MODE_SHIFT;

/**

* EXACTYLY 模式:

* 父View已经测量出子Viwe所需要的精确大小,这时候View的最终大小

* 就是SpecSize所指定的值。对应于match_parent和精确数值这两种模式

*/

public static final int EXACTLY = 1 << MODE_SHIFT;

/**

* AT_MOST 模式:

* 子View的最终大小是父View指定的SpecSize值,并且子View的大小不能大于这个值,

* 即对应wrap_content这种模式

*/

public static final int AT_MOST = 2 << MODE_SHIFT;

//将size和mode打包成一个32位的int型数值

//高2位表示SpecMode,测量模式,低30位表示SpecSize,某种测量模式下的规格大小

public static int makeMeasureSpec(int size, int mode) {

if (sUseBrokenMakeMeasureSpec) {

return size + mode;

} else {

return (size & ~MODE_MASK) | (mode & MODE_MASK);

}

}

//将32位的MeasureSpec解包,返回SpecMode,测量模式

public static int getMode(int measureSpec) {

return (measureSpec & MODE_MASK);

}

//将32位的MeasureSpec解包,返回SpecSize,某种测量模式下的规格大小

public static int getSize(int measureSpec) {

return (measureSpec & ~MODE_MASK);

}

//...

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值