在学习自定义view时,对onMeasure的理解真是很困难,网上的资料说的都大从官网上摘下来的,而且说得不明不白,看起来就犯晕。
没办法,只好自己通过实例来仔细研究一下。但研究之前,必须先对这个onMeausre的方法有个大致的理解。
onMeasure(int widthMeasureSpec, int heightMeasureSpec)Called to determine the size requirements for this view and all of its children.
Parameters
widthMeasureSpec | horizontal space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec . |
---|---|
heightMeasureSpec | vertical space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec . |
- onMeasure的两个参数用于测量水平和垂直空间大小,具体怎么测量,不得而知
- onMeasure被调用时用来决定当前view以及所有它的子view的尺寸请求
我一直搞不清楚两个参数的实际作用,所以只能通过实例来测试一下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
System.out.println(widthMeasureSpec+":"+heightMeasureSpec);
int w = getMeasureWidth(widthMeasureSpec);
int h = getMeasureHeight(heightMeasureSpec);
setMeasuredDimension(w, h); \\必须调用此方法,否则会抛出异常
}
private int getMeasureHeight(int heightMeasureSpec) {
int result = 0;
int size = MeasureSpec.getSize(heightMeasureSpec); \\每次调用此方法,测量用到的size会发生变化
int mode = MeasureSpec.getMode(heightMeasureSpec); \\根据定义的Layout_width,Layout_height,会对此值产生影响
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else if (mode == MeasureSpec.UNSPECIFIED) {
result = (int) paint.measureText("") + getPaddingLeft()
+ getPaddingRight();
} else {
result = Math.min(result, size);
}
System.out.println("Height size:" + size);
System.out.println("Height mode:" + mode);
return result;
}
private int getMeasureWidth(int widthMeasureSpec) {
int result = 0;
int size = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else if (mode == MeasureSpec.UNSPECIFIED) {
result = (int) paint.measureText("") + getPaddingTop()
+ getPaddingBottom();
} else {
result = Math.min(result, size);
}
System.out.println("Width size:" + size);
System.out.println("Width mode:" + mode);
return result;
}
请注意,当我在布局文件中,为自定义view定义如下内容时,上面代码打印出的是:
而在调用onMeasure时,以match_parent为例,最先传入的 widthMeasureSpec和heightMeasureSpec值如下图:
Mode值分别代表:
AT_MOST=-2147483648 (0x80000000) :
The child can be as large as it wants up to the specified size.
EXACTLY=1073741824 (0x40000000) :
The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
UNSPECIFIED=0 (0x00000000) :
The parent has not imposed any constraint on the child. It can be whatever size it wants.
通过上面的结果,我们来分析一下:
1.在测量width和height时,重复了四次。也就是说,每个view在onMeasure时,都会调用此方法4次来测量最终放置的位置和大小
2.在使用match_parent,wrap_content以及自定义大小时,Mode和size值会发生变化,说明Layout_width/height会对Mode和size产生影响
3.通过对比match_parent打印出的mode值,在一开始调用onMeasure时,传入的值分别为1073742302和1073742548,而当通过MeasureSpec.getMode计算之后,得到的值均为1073741824。我们把两个值一减,得到的结果是:480和724。好吧,我大胆的猜测,这就是它测量的方法。
以上有忽略或错漏的地方,希望指出!