View 中 onMeasure
今天学习android自定义组件:docs/guide/topics/ui/custom-components.html
其中有两个对布局界面影响很的方法,onDraw(),和onMeasure().
onDraw()比较好理解.onMeasure()就比较难理解一些,也更复杂些 ,引用文档中的说法就是:
实现onMeasure()方法基本需要完成下面三个方面的事情(最终结果是你自己写相应代码得出测量值并调用view的一个方法进行设置,告诉给你的view安排位置大小的父容器你要多大的空间.):
1.传递进来的参数widthMeasureSpec和heightMeasureSpec是你对你应该得出来的测量值的限制.
2. 你在onMeasure计算出来设置的width和height将被用来渲染组件.应当尽量在传递进来的width和height 声明之间.虽然你也可以选择你设置的尺寸超过传递进来的声明.但是这样的话,父容器可以选择,如clipping,scrolling,或者抛出异常,或者(也许是用新的声明参数)再次调用onMeasure()
3.一但width和height计算好了,就应该调用View.setMeasuredDimension(int width,int height)方法,否则将导致抛出异常.在Android提提供的一个自定义View示例中(在API demos 中的 view/LabelView)可以看到一个重写onMeasure()方法的
实例,也比较好理解.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
}
* 高度
* @param heightMeasureSpec
* @return
*/
private int measureHeight(int heightMeasureSpec) {
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);//父的空间大小
int h = bitmap.getHeight(); //图片的高度
int result = 0 ;
if (specMode == MeasureSpec.EXACTLY) {//父为 wrap_content
result = Math.min(h, specSize);
}else if(specMode == MeasureSpec.AT_MOST){//父为fill_parent
result = specSize;
} else {
result = specSize;
}
return result;
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) mTextPaint.measureText(mText) + getPaddingLeft()+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
直接看measureWidth()
首先看到的是参数,分别代表宽度和高度的MeasureSpec
android2.2文档中对于MeasureSpec中的说明是:
一个MeasureSpec封装了从父容器传递给子容器的布局需求.
每一个MeasureSpec代表了一个宽度,或者高度的说明.
一个MeasureSpec是一个大小跟模式的组合值.一共有三种模式.
(1)UPSPECIFIED :父容器对于子容器没有任何限制,子容器想要多大就多大.将size和mode打包或者解包为一个整型.