MeasureSpec封装了从父控件传给子控件的布局要求。每个MeasureSpec都描述了包括宽度和高度的要求。
MeasureSpec由大小(size)和模式(mode)组成,这里有三种可能的模式(mode):
UNSPECIFIED(未指定):
父控件没有对子控件进行任何的限制,子控件可以是任意大小。
EXACTLY(指定):
父控件已经指定了具体的尺寸大小给子控件,子控件必须按照指定的大小界限显示而不能随意地改变。
AT_MOST(尽可能大):
子控件可以在指定尺寸大小的范围内尽可能大地显示。
为了减少对象分配,MeasureSpec必须整形实现。
一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定控件在屏幕上的显示大小。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
onMeasure方法的两个参数是由其上一层父控件传入的,有多种情况,重写该方法时需要计算控件的实际大小,然后调用setMeasureDiemension(int, int)来设置。
onMeasure方法的两个参数widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将大小和模式组合在一起的数值。需要通过
int size = MeasureSpec.getSize(widthMeasureSpec)得到大小,通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式。
mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,MeasureSpec.AT_MOST。
MeasureSpec.UNSPECIFIED是未指明尺寸大小,这种情况不多,一般情况下是当父控件是AdapterView时通过measure方法传入的模式。
MeasureSpec.EXACTLY是精确尺寸,将控件的layout_width或layout_height指定为具体数值时或者fill_parent时,是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.AT_MOST是最大尺寸,将控件的layout_width或layout_height指定为wrap_content时,控件大小一般随着该控件的子控件或内容的变化而变化,此时
该控件尺寸只要不超过父控件允许的最大尺寸即可。因此,mode是AT_MOST时,size为父控件允许的最大尺寸。
因此,在重写onMeasure方法时要根据模式不同进行大小计算。下面的代码就是一种比较典型的方法:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false)); } private int getMeasuredLength(int length, boolean isWidth) { int specMode = MeasureSpec.getMode(length); int specSize = MeasureSpec.getSize(length); int size; int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom(); if (specMode == MeasureSpec.EXACTLY) { size = specSize; } else { size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT + padding; if (specMode == MeasureSpec.AT_MOST) { size = Math.min(size, specSize); } } return size; }
参考资料:http://www.blogjava.net/liuyanbo/archive/2012/03/15/371969.html