Android自定义View onMeasure 方法

2019-07-31  本文已影响0人  清梦星河哈
onMeasure 作用

1.一般情况重写onMeasure()方法作用是为了自定义View尺寸的规则,如果你的自定义View的尺寸是根据父控件行为一致,就不需要重写onMeasure()方法
2.如果不重写onMeasure方法,那么自定义view的尺寸默认就和父控件一样大小,当然也可以在布局文件里面写死宽高,而重写该方法可以根据自己的需求设置自定义view大小

认识 onMeasure

1.onMeasure (int widthMeasureSpec, int heightMeasureSpec)是view自己的方法
2.onMeasure 方法简单的理解就是是用于测量视图的大小,主要是用来测量自己和内容的来确定宽度和高度
3.onMeasure有两个参数 ( int widthMeasureSpec, int heightMeasureSpec),该参数表示控件可获得的空间以及关于这个空间描述的元数据.
4.widthMeasureSpec和heightMeasureSpec这两个值通常情况下都是由父视图经过计算后传递给子视图的,说明父视图会在一定程度上决定子视图的大小。

认识 MeasureSpec

在测量自定义view的大小之前,我们需要认识一个类MeasureSpec,它封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求MeasureSpec由size和mode组成。

specMode一共有三种类型,如下所示:
  1. EXACTLY
    表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,简单的说(当设置width或height为match_parent时,模式为
    EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)
  2. AT_MOST
    表示子视图最多只能是specSize中指定的大小。(当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)
  3. UNSPECIFIED
    表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。
    /**
     * 比onDraw先执行
     * <p>
     * 一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
     * 一个MeasureSpec由大小和模式组成
     * 它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;
     * EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;
     * AT_MOST(至多),子元素至多达到指定大小的值。
     * <p>
     * 它常用的三个函数:
     * 1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
     * 2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
     * 3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int minimumWidth = getSuggestedMinimumWidth();
        final int minimumHeight = getSuggestedMinimumHeight();
        int width = measureWidth(minimumWidth, widthMeasureSpec);
        int height = measureHeight(minimumHeight, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int measureWidth(int defaultWidth, int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int width;
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                //指定wrap_content时的宽度,这里的500一个替换为
                //该View宽度设置为wrap_content时,View保持完整
                //性的最小宽度。
                width = 500 + getPaddingLeft() + getPaddingRight();
                break;
            case MeasureSpec.EXACTLY:
                width = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                width = Math.max(defaultWidth, specSize);
            default:
                width = 500;
                break;
        }
        return width;
    }


    private int measureHeight(int defaultHeight, int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int height;
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                //同measureWidth相同位置的含义
                height = 800 + getPaddingTop() + getPaddingBottom();
                break;
            case MeasureSpec.EXACTLY:
                height = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                height = Math.max(defaultHeight, specSize);
                break;
            default:
                height = 800;
                break;
        }
        return height;
    }
上一篇 下一篇

猜你喜欢

热点阅读