Android全集

【Android】MeasureSpec简述

2021-01-29  本文已影响0人  littlefogcat

在 View 的 onMeasure 回调中,有两个参数widthMeasureSpecheightMeasureSpec,分别代表当前View的宽与高的MeasureSpec

1. MeasureSpec 的本质

MeasureSpec 的本质是一个整型值。
众所周知,Java/Kt 中的整型占用了 32 位;而 MeasureSpec 的前2位表示测量模式(mode),后30位表示测量大小(size),实现了一个整型保存两个信息的目的。

通过MeasureSpec.getMode(measureSpec)静态方法可以获取一个 MeasureSpec 的 mode,MeasureSpec.getSize(measureSpec)可以获取到 size。

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val wMode = MeasureSpec.getMode(widthMeasureSpec) // 水平方向的测量模式
        val wSize = MeasureSpec.getSize(widthMeasureSpec) // 水平方向的测量大小
        val hMode = MeasureSpec.getMode(heightMeasureSpec) // 竖直方向的测量模式
        val hSize = MeasureSpec.getSize(heightMeasureSpec) // 竖直方向的测量大小
    }

通过MeasureSpec.makeMeasureSpec(size, mode)静态方法,可以将 mode 与 size 合成为一个 MeasureSpec。

size 不用多说,表示宽或高的长度,单位是像素。

mode 分为三种:MeasureSpec.UNSPECIFIEDMeasureSpec.EXACTLYMeasureSpec.AT_MOST;其中,MeasureSpec.UNSPECIFIED基本不用,可以忽视。也就是说,常用的 MeasureSpec 只有EXACTLYAT_MOST两种。
顾名思义,EXACTLY即为精确模式,表示这个 ViewGroup 的宽或高是确定值size;而AT_MOST则是最大模式,表示这个 View 的宽或高最大能达到size,真实长度根据实际情况而定。

onMeasure回调中,传入的 MeasureSpec 是根据当前 View 的父容器的 MeasureSpec 和当前 View 在布局中的layout_widthlayout_height 属性决定的。

2. MeasureSpec 的计算过程

那么,onMeasure中的两个参数是如何得到的呢?
事实上,一般来讲,当一个 ViewGroup 测量自身的时候,会先遍历它的子 View,并调用子 View 的measure方法进行测量,而measure方法又会调用onMeasure回调。
也就是说,View的onMeasure回调方法中的两个参数是父容器计算并传递过来的

下表反应了正常情况下父容器是如何得到一个子 View 的 MeasureSpec 的。其中横轴表示父容器的 MeasureSpec,纵轴表示了该 View 在布局文件中设置的宽或高,表中为该 View 的 MeasureSpec 的 mode 与 size。

子View在xml中 \ 父MeasureSpec EXACTLY AT_MOST
确定的数值 mode: EXACTLY
size: 布局中设置的大小
mode: EXACTLY
size: 布局中设置的大小
wrap_content mode: AT_MOST
size: 父容器specSize
mode: AT_MOST
size: 父容器specSize
match_parent mode: EXACTLY
size: 父容器specSize
mode: AT_MOST
size: 父容器specSize

也就是说:

  1. 当布局中宽或高填写的固定值,那么对应的 mode 为 EXACTLY ,size 为填写的值;
  2. 当布局中的宽或高填写的wrap_content,那么对应的 mode 为 AT_MOST,size 为父容器的 size;
  3. 当布局中的宽或高填写的match_parent,那么顾名思义,mode 和 size 都与父容器相同。
上一篇 下一篇

猜你喜欢

热点阅读