android自定义View探索3(onMeasure深入分析一)

本文详细解析了Android中onMeasure方法的作用及MeasureSpec的工作原理。解释了onMeasure如何帮助自定义View确定其尺寸,并深入探讨了MeasureSpec如何携带测量模式与测量大小信息。

前言:

从去年7月到北方马上一年了,一年的外包生活有喜有泪,喜的是技术提升很快,为人成熟了,在上海时总认为自己是小孩子;泪的话远离家乡,没有家人,朋友不多。但是总归在进步,不习惯也会习惯。哈哈加油吧。


一 onMeasure简介


onMeasure是用来干嘛的?measure是测量的意思,从字面上我们就可以知道它是用来测量视图的宽高尺寸的。问题来了为什么要在onMeasure()里测量尺寸呢?


在上篇文章android自定义View探索2我们已经看到了,XML使用我们自定义View的时候直接设置wrap_content无效。

为什么无效?


因为我们没有对自定义View设置大小,而绘制到屏幕中的View必须指定具体的大小,没有指定大小就像上篇文章中演示的默认是MatchParent,一般情况下这很能满足我们

需求,这时候就要用到onMeasure.

先来看看onMeasure的源码

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

以上是View.class中自定义View的源码,android中每一个控件都会重写它,有兴趣可以去看看。

我们看到它有两个参数widthMeasureSpec、heightMeasureSpec,那么这两个参数用来干吗的呢?

这两个值分别用于确定视图的宽度和高度的规格和大小,什么宽度和规格和高度和大小,怎么包含这么多信息呢?对,你没有看错,那么一个int怎么可以存放这么多信息的

呢?下面我们来深入分析MeasureSpec。


二 MeasureSpec详解


MeasureSpec是干什么用的?

  任玉刚的《Android开发探索》是这么说的:

“确切来说,MeasureSpec在很大程度上决定了一个View控件的尺寸规格。”

很大程度上难道还有其他因素?除了自身因素外他还受父容器的影响。那么父容器是怎么影响View控件的尺寸规格的呢?

在测量的过程中,系统会将View的LayoutParams跟据父容器所施加的规则转换成对应的MeasureSpec,所以MeasureSpec是受到父容器影响的,还有宽高是测量的宽高,

不一定等于最终的宽高。

前面我们提到过一个问题,MeasureSpec怎么包含这么多信息呢?

MeasureSpec是一个32位的int值,它由specMode和SpecSize组成;其中高2位代表SpecMode,低30位代表SpecSize。那么SpecMode和SpecSize分别代表了什么呢?为

什么把SpecMode和SpecSize打包到一起呢?


先来回答第一个问题,SpecMode和SpecSize分别用来干什么的?

SpecMode:测量模式。

SpecSize:在某种测量模式下的规格大小


第一个问题解决了再来看看第二个问题,为什么把SpecMode和SpecSize打包到一起呢?

解决这个文题前先来看看源码:

View.class

        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;
        public static final int EXACTLY     = 1 << MODE_SHIFT;
        public static final int AT_MOST     = 2 << MODE_SHIFT;

        
        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }
        
        public static int getMode(int measureSpec) {
            //noinspection ResourceType
            return (measureSpec & MODE_MASK);
        }
        
        public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
        }

看看三个方法的功能吧:

1.makeMeasureSpec方法:这个方法通过将SpecMode和SpecSize打包成一个int值。从中我们也可以发现,把SpecMode和SpecSize打包成一个int值是为

了避免过多的对象内存分配。

2.getMode方法:这个方法把SpecMode解包了。

3.getSize方法:这个方法把SpecSize解包了。


从以上代码中我们可以看出SpecMode的取值模式有三种:

UNSPECIFIED.


这种模式下开发人员可以将View设置成任意大小,没有任何限制,不过这种模式在开发中用的比较少。

EXACTLY:


这种模式下View的最终大下就是SpecSize所指定的值,它对应的大小可以是LayoutParams的MatchParent或具体的值。我们在上篇文章中wrap_content全屏默认就是这种模式。


AT_MOST:

表示View的大小不能超过SpecSize,当然开发者也可以自己设置大小。



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值