view的测量在onMeasure()方法中进行。
Android系统提供给我们一个类--MeasureSpec类。
测量模式有三种:
EXACTLY:精确值模式,将控件的layout_width或layout_heigh属性指定为具体数值时,android:layout_with="100dp"。或者指定为match_parent属性时。
AT_MOST:最大值模式,layout_width或layout_heigh属性设为wrap_content时。控件大小随控件的子空间或内容的变化而变化,不要超过父控件允许的最大尺寸即可。
UNSPECFIED:不指定其大小的测量模式,View像多大就多大,通常在绘制自定义view时才会使用。
View默认的onMeasure()方法只支持EXACTLY模式,所以可以指定控件的具体宽高值或者match_parent属性,
如果要自定义的view支持wrap_content属性,就必须重写onMeasure()方法。
@Override可以看到,onMeasure()方法最终调用的是
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
onMeasure默认的实现仅仅调用了setMeasuredDimension,setMeasuredDimension函数是一个很关键的函数,它对View的成员变量mMeasuredWidth和mMeasuredHeight变量赋值,而measure的主要目的就是对View树中的每个View的mMeasuredWidth和mMeasuredHeight进行赋值,一旦这两个变量被赋值,则意味着该View的测量工作结束。
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= MEASURED_DIMENSION_SET; } 所以我们的实现代码如下:public class MyMeasure extends View{ public MyMeasure(Context context) { super(context); } public MyMeasure(Context context, AttributeSet attrs) { super(context, attrs); } public MyMeasure(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); //调用 setMeasuredDimension()将测量好的宽高值传递进去 setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeigh(heightMeasureSpec)); } /** * 获取宽度测量值 * @param measureSpec * @return */ private int measureWidth(int measureSpec){ int result=0; int specMode=MeasureSpec.getMode(measureSpec);//宽度的测量模式 int specSize=MeasureSpec.getSize(measureSpec);//宽度的测量值的大小 if (specMode==MeasureSpec.EXACTLY){//EXACTLY模式 result=specSize; }else { result=400; if (specMode==MeasureSpec.AT_MOST){ result=Math.min(result,specSize); } } return result; } private int measureHeigh(int measureSpec){ int result=0; int specMode=MeasureSpec.getMode(measureSpec);//高度的测量模式 int specSize=MeasureSpec.getSize(measureSpec);//高度测量值的大小 if (specMode==MeasureSpec.EXACTLY){//EXACTLY模式 result=specMode; }else { result=500; if (specMode==MeasureSpec.AT_MOST){ result=Math.min(result,specSize); } } return result; } }<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.hybunion.customview.activity.MyMeasureActivity"> <com.hybunion.customview.view.MyMeasure android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#567890" /> </RelativeLayout>