MeasureSpec介绍及使用详解

MeasureSpec是Android中重要的一个测量工具类,主要用于计算View的宽高、确定View的位置以及子View的布局等操作。在Android中,每个View都可以通过MeasureSpec来进行测量,MeasureSpec具有如下三种测量模式:

1. UNSPECIFIED:未指定模式。这种模式表示View大小不受限制,可以随意增大或缩小,通常不会用到该模式。

2. EXACTLY:精确模式。这种模式表示View大小已经被明确指定,View的大小就是MeasureSpec的size变量值,在布局中使用wrap_content或者具体的数值来指定View的大小,会使用该模式。

3. AT_MOST:最大值模式。该模式表示View大小只能达到MeasureSpec的size变量值,不能超过该大小,在布局中使用了match_parent 或者具体的数值来指定View大小,会使用该模式。

在测量View的过程中,我们需要配合MeasureSpec的测量模式和View所处的MeasureSpec来进行测量。其中,View所处的MeasureSpec是由ViewGroup在布局过程中传入给子View的,而子View需要根据View所处的MeasureSpec和自身的布局要求来计算出自己在屏幕上需要占据的大小。MeasureSpec包含两个变量:size和mode,size表示大小,mode表示模式,我们可以通过MeasureSpec的常量值来快速获取对应的测量模式。

我们来看一下MeasureSpec的使用方法:

1. 在View的onMeasure() 方法中,通过MeasureSpec的各种常量来进行测量:

```

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

// 根据测量模式来进行View的宽高计算

if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {

// 精确模式,直接使用MeasureSpec的size变量值

setMeasuredDimension(widthSize, heightSize);

} else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {

// 最大值模式,宽高设置为wrap_content时使用

int size = Math.min(100, Math.min(widthSize, heightSize));

setMeasuredDimension(size, size);

} else {

// 其他模式,使用默认大小

setMeasuredDimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);

}

}

```

2. 在ViewGroup的onMeasure() 方法中,根据子View的需求计算出ViewGroup的尺寸:

```

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int childCount = getChildCount();

int maxWidth = 0;

int maxHeight = 0;

for (int i = 0; i < childCount; i++) {

View child = getChildAt(i);

measureChild(child, widthMeasureSpec, heightMeasureSpec);

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

if (childWidth > maxWidth) {

maxWidth = childWidth;

}

if (childHeight > maxHeight) {

maxHeight = childHeight;

}

}

setMeasuredDimension(maxWidth, maxHeight);

}

```

这里还需要注意,View的测量过程会在View的onMeasure()方法中进行,而ViewGroup的测量过程会在onMeasure()方法中计算子View的大小并得出自身的大小。

最后,我们来举一个MeasureSpec的应用例子,比如我们现在需要设计一个瀑布流布局,那么我们需要在onMeasure()方法中测量出每个子View的大小和位置:

```

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int childWidthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() / 2, MeasureSpec.EXACTLY);

int left = 0;

int top = 0;

for (int i = 0; i < getChildCount(); i++) {

View childView = getChildAt(i);

// 这里测量子View的高度是未指定模式,以适配子View的自适应大小

int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

childView.measure(childWidthSpec, childHeightSpec);

int childHeight = childView.getMeasuredHeight();

if (left + childView.getMeasuredWidth() > getMeasuredWidth()) {

left = 0;

top += childHeight;

}

childView.layout(left, top, left + childView.getMeasuredWidth(), top + childHeight);

left += childView.getMeasuredWidth();

}

}

```

在这个例子中,我们首先根据父View的宽度和子View的数量计算出每个子View的宽度大小,并将高度未指定模式,然后通过for循环依次测量子View的大小,并计算出每个子View在父View中的位置。 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.37seo.cn/

点赞(92) 打赏

评论列表 共有 1 条评论

一夕意相左 1年前 回复TA

这辈子最幸运的事就是遇见你。

立即
投稿
发表
评论
返回
顶部