android开发:自定义View三步走(一):测量

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * @Author: david.lvfujiang
 * @Date: 2020/1/16
 * @Describe:
 */
public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        //画个圆
        canvas.drawCircle(200,200,200,paint);
    }
}

  <com.example.MyView
        android:id="@+id/myView"
        android:background="@color/colorPrimaryDark"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"></com.example.MyView>

我们自定义一个view,默认测量,在onDraw()画一个圆,在xml中给view的宽度、高度都是wrap_content,发现view会沾满整个父控件

在这里插入图片描述

如果我们想自己设置view的高度和宽度则需要重写onMeasure()

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * @Author: david.lvfujiang
 * @Date: 2020/1/16
 * @Describe:
 */
public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //高度自己计算,根据圆的半径知道圆的高度是400像素
        int height = 400;
     	//解析父类传入的限制
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        //尺寸修正
        resolveSize(400,widthMeasureSpec);
        resolveSize(width,heightMeasureSpec);
        //保存尺寸
        setMeasuredDimension(width,height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        canvas.drawCircle(200,200,200,paint);
    }

}

onMeasure()方法传入的俩个参数是父控件对子view的宽度和高度限制,它们由父控件计算得到。使用MeasureSpec类可以对它们进行解析得到尺寸和限制的规则。限制规则的分类:
UNSPECIFIED:不限制
AT_MOST:任意大小但不能超过父控件
EXACTLY:固定值
如果限制规则是AT_MOST,则解析得到的尺寸是父类最大的高度或者宽度。如果是UNSPECIFIEDEXACTLY解析得到的尺寸就是在xml内指定的尺寸。
resolveSize()是尺寸修正的方法,例如view的限制是AT_MOST,它不能超过父控件的范围,但是我们自己计算出的高度已经超过父控件的范围,这时候我们就需要修正尺寸,不然会发现异常。

public static int resolveSize(int size, int measureSpec) {
         int result = size;
         int specMode = MeasureSpec.getMode(measureSpec);
         int specSize =  MeasureSpec.getSize(measureSpec);
         switch (specMode) {
         case MeasureSpec.UNSPECIFIED:
             result = size;
             break;
         case MeasureSpec.AT_MOST:
         	//size小于父类范围则直接返回,大于则返回specSize,specSize是父类最大的范围尺寸
             result = Math.min(size, specSize);
             break;
         case MeasureSpec.EXACTLY:
         	//限制是EXACTLY,精确值。则直接返回
             result = specSize;
             break;
         }
         return result;
     }

整体的测量流程大致就是:自己测量view需要的高度和宽度,调用resolveSize()方法修正尺寸,确保符合父类的限制。最后调用 setMeasuredDimension(width,height);方法保存。
上诉例子是根据圆来计算view的高度,宽度则引用父类传进来的尺寸,因此执行得到:
在这里插入图片描述

发布了194 篇原创文章 · 获赞 42 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_39027256/article/details/104003630