您的位置:首页 > 移动开发 > Android开发

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

2017-06-15 16:27 483 查看
前言:

从去年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,当然开发者也可以自己设置大小。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: