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的高度,寬度則引用父類傳進來的尺寸,因此執行得到:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章