一、前言
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的实际尺寸了。