Android开发者必须要了解的View测量过程(View的工作过程之Measure过程)

View的工作原理之测量过程


目录


1. 详细测量过程

View的详细测量过程

1.1 测量过程到底要测量什么?

  1. View的宽 对应的属性为: mMeasuredWidth
  2. View的高 对应的属性为: mMeasuredHeight

1.2 详细过程说明

  1. 追溯到最根部,测量是从一个ViewGroup开始
  2. 先是调用到measure方法,在measure方法中回调onMeasure
  3. 如果onMeasure中对子节点进行了测量,则测量子节点

1.3 测量概念说明

1.3.1 ViewGroup测量的是ViewGroup的宽高,不是内容的宽高

ViewGroup嵌套View的情况下,测量的是ViewGroup的宽高,不是ViewGroup中内容的宽高。

测量ViewGroup时测量的宽高

由上图可知,测量的数据上实际上是:

  1. 宽度 : parentWidth
  2. 高度 : parentHeight

因为内部内容的高度,或者宽度是可以大于容器的宽高的,所以可以这样认为,只有当宽高设置为wrap_content时,ViewGroup的测量才会与内部的View有关

1.3.2 View测量的是View的宽高,不是内容的宽高

一般情况下,View是用来显示一些内容的,那么测量View时,测量的也是View的宽高,而不是内容的宽高

测量View时测量的宽高

由上图可知,测量的数据上实际上是:

  1. 宽度 : width
  2. 高度 : height

因为内部内容的高度,或者宽度是可以大于容器的宽高的,所以如果如果想根据内容变化,需要计算内容的宽度和高度。

2. 一般情况下的测量过程中要做的事情(通常的操作)

  1. onMeasure中,根据实际情况,实现测量操作
  2. 将测量出来的值,通过setMeasuredDimension设置到View的属性上

一般情况下的测量过程中要做的事情

2.1 测量

测量过程实际上是根距实际的需求,定义算法来算出宽高,也是测量过程中比较重要的一步。由于measure方法是不可重新写的,所以,测量过程一般都是通过重写onMeasure方法来定义。

2.1.1 ViewViewGroup不同测量

ViewViewGroup不同,因为View没有子节点,只需要测量即可。而不同的ViewGroup会可能有不同的测量规则,因为它可能根据子节点来变化,所以一般ViewGroup需要测量子节点,而且还需要根据子节点的宽高来计算自己的宽高。ViewGroup提供了测量子节点的方法。

一般情况下,ViewGroup需要自定义测量过程,并且需要测量子节点。

2.1.2 MeasureSpec

在重写onMeasure时发现,传递了两个int值,这两个值是:int widthMeasureSpec, int heightMeasureSpec,实际上这是一个32位int值,高两位代表SpecMode,低30位代表SpecSize

  1. SpecMode指的是测量模式
  2. SpecSize指的是在某种测量模式下的规格大小

SpecMode有三个值,定义在MeasureSpec类中

  1. UNSPECIFIED,父容器不对View有任何限制,用于系统内部
  2. EXACTLY,精确值,这个时候View的最终大小就是SpecSize所指定的值, 对应于LayoutParam中的match_parent或者直接指定具体值。
  3. AT_MOST,父容器制定了一个可用大小,即SpecSizeView的大小不能大于这个值,对应于LayoutParams中的wrap_content
如何获取到SpecModeSpecSize呢??
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 获取SpecMode
    MeasureSpec.getMode(widthMeasureSpec);
    MeasureSpec.getMode(heightMeasureSpec);
    // 获取SpecSize
    MeasureSpec.getSize(widthMeasureSpec);
    MeasureSpec.getSize(heightMeasureSpec);
    ......
}

2.1.3 自定义实现测量

onMeasure时,ViewGroup一般都需要实现此方法,并且要测量子节点。而View一般直接实现指定测量出的宽高即可。

但是有时候业务需求,需要自定义测量宽高,这时可以根据不同的测量模式进行不同的实现:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int pWidth=0;
    int pHeight=0;

     // 获取测量模式
    int widthMeasureSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMeasureSpecMode = MeasureSpec.getMode(heightMeasureSpec);

    switch (widthMeasureSpecMode) {
    case MeasureSpec.UNSPECIFIED:
        ........ // 自定义实现
        break;
    case MeasureSpec.AT_MOST:
         ........  // 自定义实现
        break;
    case MeasureSpec.EXACTLY:
        ........ // 自定义实现
        break;
    }

    switch (heightMeasureSpecMode) {
    case MeasureSpec.UNSPECIFIED:
        ........ // 自定义实现
        break;
    case MeasureSpec.AT_MOST:
        ........ // 自定义实现
        break;
    case MeasureSpec.EXACTLY:
        ........ // 自定义实现
        break;
    }

    setMeasuredDimension(pWidth, pHeight);
}

2.2 设置测量的值

当回调onMeasure时,如果想设置自定义实现的测量后的结果,可以通过protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)来设置,这个方法必须onMeasure()时被调用!

2.2.1 View的默认实现
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

看到,在View的默认实现中调用了getDefaultSize(int size, int measureSpec)方法用来获取宽高,

2.2.2 getDefaultSize的实现
public static int getDefaultSize(int size, int measureSpec) {
    int result = size;

    // 获取测量模式
    int specMode = MeasureSpec.getMode(measureSpec);
    // 获取测量到的大小
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}



我的个人网站

推荐视频教程:

Android从整体到局部系列视频教程戳我

广告:

我使用的装备:程序员必备 | 不伤关节 | 手感好 | 静电容 | Plum键盘|Niz键盘 戳我



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值