返回

从图到源码,你一定能读懂View的Measure方法

Android

前言

本篇是《读懂View》系列的第二篇文章,在上一篇文章中,我们介绍了View的绘制流程,了解了View的绘制过程主要分为三个步骤:measure、layout和draw。

本篇文章将正式开始讲解View的这三大绘制方法,本篇将讲述第一个方法—— Measure 方法。

Measure方法

Measure方法是View绘制的第一步,它的作用是确定View的大小,也就是确定View在屏幕上所占用的空间。

Measure方法的原型如下:

protected void measure(int widthMeasureSpec, int heightMeasureSpec)

其中,widthMeasureSpec和heightMeasureSpec是两个整型参数,它们表示了父View对当前View的测量约束条件。

这两个参数的具体格式如下:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, mode);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, mode);

其中,width和height是父View希望子View的大小,mode是测量模式,它可以是以下三种之一:

  • EXACTLY:父View希望子View的大小为width和height。
  • AT_MOST:父View希望子View的大小不超过width和height。
  • UNSPECIFIED:父View对子View的大小没有任何限制。

Measure方法的实现

Measure方法的实现比较复杂,这里我们只简单介绍一下它的基本原理。

Measure方法首先会调用子View的onMeasure方法,子View的onMeasure方法会根据父View的测量约束条件来计算自己的大小,然后将计算结果返回给父View。

父View拿到子View的大小后,会根据自己的测量约束条件来计算自己的大小,然后将计算结果返回给自己的父View。

以此类推,直到根View计算出自己的大小,整个Measure过程就结束了。

测量模式

在Measure方法中,测量模式是一个非常重要的概念。

测量模式有三种:EXACTLY、AT_MOST和UNSPECIFIED。

  • EXACTLY:父View希望子View的大小为width和height。
  • AT_MOST:父View希望子View的大小不超过width和height。
  • UNSPECIFIED:父View对子View的大小没有任何限制。

不同的测量模式,子View的计算方式是不同的。

  • EXACTLY模式 :子View的大小必须为width和height。
  • AT_MOST模式 :子View的大小不能超过width和height,但可以小于width和height。
  • UNSPECIFIED模式 :子View的大小可以是任意值。

源码案例分析

为了更好地理解Measure方法的工作原理,我们来看一个具体的源码案例。

public class MyView extends View {

    private int mWidth;
    private int mHeight;

    public MyView(Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 获取父View的测量约束条件
        int parentWidthMeasureSpec = MeasureSpec.getMode(widthMeasureSpec);
        int parentHeightMeasureSpec = MeasureSpec.getMode(heightMeasureSpec);

        // 获取父View希望的子View的大小
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);

        // 根据父View的测量约束条件来计算自己的大小
        int width;
        int height;
        if (parentWidthMeasureSpec == MeasureSpec.EXACTLY) {
            width = parentWidth;
        } else {
            width = mWidth;
        }

        if (parentHeightMeasureSpec == MeasureSpec.EXACTLY) {
            height = parentHeight;
        } else {
            height = mHeight;
        }

        // 设置自己的大小
        setMeasuredDimension(width, height);
    }
}

在这个例子中,MyView的onMeasure方法首先获取了父View的测量约束条件,然后根据父View的测量约束条件来计算自己的大小。

如果父View的测量约束条件是EXACTLY,那么MyView的大小就必须为父View希望的大小。

如果父View的测量约束条件是AT_MOST,那么MyView的大小就不能超过父View希望的大小,但可以小于父View希望的大小。

如果父View的测量约束条件是UNSPECIFIED,那么MyView的大小可以是任意值。

总结

Measure方法是View绘制的第一步,它的作用是确定View的大小。

Measure方法的实现比较复杂,但基本原理并不难理解。

在Measure方法中,测量模式是一个非常重要的概念。

不同的测量模式,子View的计算方式是不同的。

希望本文能帮助您理解View的Measure方法。