本文主要是自己学习的笔记,想学习的建议直接去看HenCoder视频教学地址
不同于上一篇:修改控件尺寸,有些时候需要自己计算控件尺寸而不是修改已经计算好的,所以在重写onMeasure的时候,就不需要调用super. onMeasure(),直接自己去算好宽高,然后setMeasuredDimension设置进去就好了。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
...
// 自定义宽高
width = ...;
height = ...;
// 过滤宽高(检查宽高是否合格)
width = resolveSize(width, widthMeasureSpec);
height = resolveSize(height, heightMeasureSpec);
// 设置宽高
setMeasuredDimension(width, height);
}
上面代码有很重要的一步:resolveSize(),因为控件并不是想自己大多就能多大,我们算好的尺寸,或者说希望的尺寸,并不一定能成为最后的尺寸,比如父控件空间不足。所以要调用resolveSize去过滤一下,resolveSize是View中已经实现了的方法,点击去看下具体做了什么事情,resolveSize的代码大致如下:
// resolveSize的简化实现,并不是完整源码
public static int resolveSize(int size, int measureSpec){
final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);
final int result;
switch (specMode) {
case MeasureSpec.AT_MOST:
if (specSize < size) {
result = specSize;
} else {
result = size;
}
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
case MeasureSpec.UNSPECIFIED:
default:
result = size;
}
return result ;
}
在onMeasure中的两个参数widthMeasureSpec、heightMeasureSpec并不只包含了size,还包含了mode,mode只指父控件对其的限制,有三种AT_MOST(最大值)、EXACTLY(精确值)、UNSPECIFIED(无限制)。
resolveSize方法分析:
调用resolveSize过滤其实就是根据mode计算出准确的size返回,而并非子控件想自己多大就大多。
size:我们计算出来的值,也可以说是子控件自己希望的值。
specSize:从onMeasure的参数中获取的,是父控件调用子控件的measure()方法的时候传入的,是父控件对子控件的限制。
- 当mode是AT_MOST,就是父控件规定了子控件的最大值,specSize就是这个最大值,所以:
return Math.min(size, specSize)
- 当mode为EXACTLY,就是父控件要精确的控制子控件大小,子控件的大小必须是specSize,所以:
return specSize
当mode为UNSPECIFIED,也就是父控件对子控件没限制,子控件的大小可以为其自己希望的大小,所以:
return size
感谢HenCoder