View的测量

  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
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
可以看到,onMeasure()方法最终调用的是

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>

效果如下:

              View的测量_第1张图片










你可能感兴趣的:(Android之View)