Android自定义控件

来源:互联网 发布:c语言韩信点兵点人数 编辑:程序博客网 时间:2024/06/05 20:42

概述

在现实生活中,如果我们要去画一个图形,必须先知道他的大小和位置,同样,在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的大小。

原创粉丝点击