自定义View基础知识,View的测量

一、前言

Android自定义View中大致主要分为以下几个步骤:
1、测量(onMeasure)
2、绘制(onDraw)
3、重写touch事件(onTouchEvent)

自定义ViewGroup中呢则大致分为:
1、测量(onMeasure)
2、布局(onLayout)
3、重写touch事件(onTouchEvent)

而这里主要讲该如何去测量。测量实际上顾名思义就是要计算出我这个View在屏幕中显示所要占用多大的空间。并且告诉我们的系统。

二、测量模式

ok!那么要对View进行测量,首先我们要明白View的三种测量模式的意义。

1、EXACTLY

在没有重写onMeasure()方法的情况下,每个View默认的测量方式既是EXACTLY,能够响应精确的dp值作为View的layout_width和layout_height,也能够去响应match_parent。

2、AT_MOST

AT_MOST对应的既是响应warp_content,如果View需要去支持warp_content的话,则必须去重写onMeasure()方法。

3、UNSPECIFIED

UNSPECIFIED的话并不直接体现在xml布局文件的申明中,他代表着我们的View的大小有我们自己去在View的测量过程中自己给予,想要多大就多大。

并且需要提上一点,这三种测量方式均是MeasureSpec类中的一个静态整型常量。

三、测量步骤

1、重写onMeasure()方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

2、分别去测量宽高。

这里可以贴上一个模板代码。

private int measuredWidth(int widthMeasureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(widthMeasureSpec);
    int specSize = MeasureSpec.getSize(widthMeasureSpec);
    
    if (specMode == MeasureSpec.EXACTLY) {
        result = specSize;
    }else {
        result = 200;
        if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
    }
    
    return result;
}

int specMode = MeasureSpec.getMode(widthMeasureSpec);能够获取到当前的的测量模式
int specSize = MeasureSpec.getSize(widthMeasureSpec);能够获取当前的实际尺寸

当模式为EXACTLY的时候我们就只要顺其自然的给原值就行。
如果不是呢?那证明是AT_MOST或UNSPECIFIED中的某一个。那么我们需要给一个给一个我们所期望的值,上面代码将这个值给了200,实际上我们可以根据View中内容的大小去给。
如果是UNSPECIFIED的话很明显,我们只要给我们期望的值就行了,但是如果是AT_MOST也就是warp_content的话,我们需要取期望值和原值中最小的那一个作为我们最终的测量结果。

上诉代码为测量width,测量height的方式完全一样。

3、将测量结果传递出去。

在自定义View中,父类View这个类的onMeasure方法最终会将测量完毕的值调用setMeasuredDimension方法传递进去。如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

所以我们重写的onMeasure方法同样的去调用setMeasuredDimension方法将测量完的值传递给他即可完成我们的测量。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(measuredWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec));
}

四、ViewGroup的测量

ViewGroup的测量重点就不在这个ViewGroup的自身了,而在它的每一个子View上,我们需要去测量每一个子View的实际大小。大致的代码如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int ChildCount = getChildCount();
    for (int i = 0; i < ChildCount; i++) {
        measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

可以看到我们先是拿到了子View的总个数,再去遍历,通过measureChild方法一个一个的测量。测量完毕之后呢,我们就可以通过子View的对象去调用getMeasuredWidth()或getMeasuredHeight()拿到这个子View的实际尺寸了。

    原文作者:逝水比喻时光
    原文地址: https://www.jianshu.com/p/09c51752f5fa
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞