View测量之onMeasure方法

自定义View有三个常用方法可以调用,onLayout设置view的位置,onMeasure设置宽高,onDraw绘制view,这篇来写其中的一个OnMeasuer方法。

在现实生活中,如果我们要去画一个图形,就必须知道他的大小和位置。同样,Android系统在绘制View前,也必须对View进行测量,即告诉系统该画一个多大的View。这个过程在onMeasure方法中进行。

举个栗子来展示onMeasure的作用:
新建个类继承自View

package com.example.antact.onmeasuretest;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by Antact on 2017/5/13.
 */

public class TestView extends View{

    public TestView(Context context) {
        super(context,null);
    }

    public TestView(Context context, AttributeSet attrs) {
        super(context, attrs,0);
    }

    public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
    }

    private int measureHeight(int heightMeasureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);
        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }else {
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);//Math中的min方法是用来比较两个数大小的,比较结果中返回较小的那个数值
            }
        }
        return result;


    }

    private int measureWidth(int widthMeasureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }else {
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);
            }
        }
        return result;

    }

}

在 IDE 中按住Ctrl查看super.onMeasuer( )方法,系统最终会调用setMeasuerdDimension(int measuredWidth,int measuredHeight)方法将测量后的宽高值设置进去,从而完成测量工作。

所以这里重写了onMeasure方法,调用setMeasuerdDimension方法,把两个参数写成measureWidth和measureHeight方法。

Android系统给我们提供了一个设计短小精悍缺功能强大的类——MeasureSpec类,通过它来帮助我们测量View。MeasureSpce是一个32位的int值,其中高2位为测量的模式,低30位为测量的大小,在计算中使用位运算的原因是为了提高并优化效率。

测量的模式可以分为以下三种。

  • EXACTLY
    即精确模式,当我们将空间的layout_width属性或layout_height属性指定为具体数值是,比如android:layout_width=”100dp”,或者指定为match_parent属性时候,系统使用的是EXACTLY模式

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

  • UNSPECIFIED
    这个属性比较奇怪——它不指定其大小测量模式,View想多大就多大,通常情况下载绘制自定义View时才会使用。

View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式。控件可以响应你指定的具体宽高值或者是match_parent属性。而如果要让自定义View支持wrap_content属性,那么就必须重写onMeasure()方法来指定wrap_content时的大小。

View定义好了,接下来再activity_main.layout里面调用试试

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.antact.onmeasuretest.TestView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#000"/>
</RelativeLayout>

这里写图片描述

我们把layout_width和layout_height都设置成wrap_content,可以看到这里是一个宽高都是200px(注意这里单位是px,并不是我们常用的dp!)的正方形,即这个View的最小宽高是200px(当然要在父布局允许的情况下,如果父布局宽是190px,那么这个View宽也只能是190px了)。

综上所述,onMeasure的作用就是指定View的layout_width和layout_height在wrap_content的情况下的最小值。

/参考自Androd群英传

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值