我们在自定义控件的时候,通常会涉及到测量的问题,onMeasure方法就是让我们的控件测量自身的一个方法,这里给出系统自带的一个现成的方法:
1.一次测量所有的孩子
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
适应于所有孩子的宽和高都一致的情况,方法中的参数是你作为父容器,推荐给孩子的宽和高极其计算模式
2.一次测量一个孩子
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
final LayoutParams lp = child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
这个方法用于测量一个孩子,其实第一个方法里面就是用了这个方法.第一个方法比较简便,但是第二个方法比较灵活,可以让每一个孩子的宽和高都不一样,参数不再做解释,应该都看得懂
博客发现一个容易引起误解的地方:就是这个方法所使用的参数名字,parentWidth....这样子的参数意思就是说父容器宽的Measure 或者 高的Measure 而这里的用处完全是孩子用到的,所以这里博客认为这个参数的名称起的有问题,比较容易引起误解,如果哪位大大知道我说的有错误,还请指正,欢迎留言给我!
3.获取一个MeasureSpec对象(MeasureSpec就是保存计算模式和值的一个值,一个值中可以解析出两个值)
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
//......
}
由于代码比较长,故不贴出中间的实现了,这个方法是根据推荐的spec(宽或高计算模式和宽或高的值),padding(左边距+右边距),chileDimension(孩子的宽或者高的值,可以是LayoutParams.WRAP_CONTENT(包裹),LayoutParams.MATCH_PARENT(填充))
4. 获取容器本身的宽或者高
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;
}
这个方法和第三个是类似的,只不过第三个针对的是孩子,也就是容器中的View对象,这个方法针对的是自身,也就是容器本身,代码也比较简单,其实就是帮你计算容器本身的宽和高,如果是包裹的时候,就采用传入的第一个参数,所以第一个参数size是容器自身包裹的时候用到的,而容器自身包裹的宽或者高的值就是根据你这个自定义控件自身而定.也就是在包裹的时候size就需要你自己计算出来