Android自定义控件 - View的绘制

概述

在现实生活中,如果我们要去画一个图形,必须先知道他的大小和位置,同样,在Android中,在绘制一个View前,也必须要先去测量将要绘制的View的大小,这个测量过程在onMeasure()方法中进行。

MeasureSpec类

Android系统给我们提供了一个强大的类MeasureSpec,通过这个类,可以帮助我们测量测量View,MeasureSpec是一个32位的int值,其中高2位代表测量的模式,低30位代表测量的大小
所以说MeasureSpec类中包含View测量的模式和大小。

那么什么事测量的模式,什么是测量的大小呢?

测量的模式

测量有三种模式

  • EXACTLY (精确值模式): 当我们测量的控件的layout_width属性或者layout_height属性指定为具体的数值,比如android:layout_width="200dp",或者指定为match_parent,比如android:layout_height="match_parent"时,系统使用EXACTLY模式。

  • AT_MOST(最大值模式):当我们测量的控件的layout_width属性或者layout_height属性指定为wrap_content时,即控件的大小一般随着其子空间或者内容的内容的变化而变化,此时控件的大小只要不超过父控件所允许的最大尺寸即可。

  • UNSPECIFIED (未指定模式):它未指定控件的大小测量模式,View想多大就多大,通常像ScrollView中这种类型控件使用这种模式。

onMeasure方法默认只支持EXACTLY模式,所以当我们自定义控件的时候,如果不去重写OnMeasure方法,就只能使用EXACTLY模式,控件可以响应你指定的具体的宽高值,或者match_parent属性。 如果你想要你的自定义View支持wrap_content属性,就必须要重写onMeasure()方法来制定wrap_content时的大小。

通过Meassure类,我们就获取了View的测量模式和View想要绘制的大小,有了这些信息,我们就可以控制View最后显示的大小。

实例讲解

我们写一个类继承View,重写它的onMeasure()方法

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

我们点击进入**super.onMeasure()**方法中,查看其源码

  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

可以发现其内部使用了**setMeasuredDimension(int measuredWidth, int measuredHeight)**方法将最终测量得到的宽高设置进去,从而完成测量的工作。所以,当我们在自定义控件时,通过重写onMeasure()方法,最终就是把测量后的结果作为参数设置给setMeasuredDimension(int measuredWidth, int measuredHeight)方法。

我们把自己定义控件的onMeasure方法进行重写:

 //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidthSize = measureWidth(widthMeasureSpec);
        int measureHeightSize = measureHeight(heightMeasureSpec);

        setMeasuredDimension(measureWidthSize, measureHeightSize);  // 设置测量结果
private int measureWidth(int measureSpace) {
        // 获取测量模式
        int mode = MeasureSpec.getMode(measureSpace);
        // 获取测量的大小
        int size = MeasureSpec.getSize(measureSpace);

        if(mode == MeasureSpec.EXACTLY){  // 如果测量模式为精确测量,则直接返回测量的大小
            return size;
        } else {
            int maxSize = 200;
            if(mode == MeasureSpec.AT_MOST){   // 如果是至多测量,
                return Math.min(maxSize, size);    // 设置View的大小最大不能超过200
            }
        }
        return 0;
    }

其中measureHeight()方法和measureWidth()方法内容一样。

现在我们在布局文件中设置这个使用这个自定义控件。
先给一个固定的值:

<com.itdujun.custom_view.CustomerView
        android:layout_width="400px"
        android:layout_height="400px"
        android:background="@color/colorAccent"/>

运行会查看结果:

这里写图片描述

然后在设置为match_parent:

<com.itdujun.custom_view.CustomerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"/>

这里写图片描述

设置为wrap_content

<com.itdujun.custom_view.CustomerView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"/>

这里写图片描述

因为我们在onMeasure()方法中,代码为如果测量模式为AT_MOST时,起最小尺寸为200px,所以这里显示200px的大小。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值