MeasureSpec和LayoutParams的对应关系
当View采用固定宽/高的时候,不管父容器的MeasureSpec是什么,View的MeasureSpec都是精确模式并且其大小遵循Layoutparams中的大小。
当View的宽/高是match_parent时,如果父容器的模式是精准模式,那么View也是精准模式并且其大小是父容器的剩余空间;如果父容器是最大模式,那么View也是最大模式并且其大小不会超过父容器的剩余空间。
当View的宽/高是wrap_content时,不管父容器的模式是精准还是最大化,View的模式总是最大化并且大小不能超过父容器的剩余空间。
具体流程
1. View的measure过程
View的measure过程由其measure方法来完成,measure方法是一个final类型的方法,这意味着子类不能重写此方法,在View的measure方法中会去调用View的onMeasure方法,因此只需要看onMeasure的实现即可。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
这里很显然根据不同的 SpecMode 值来返回不同的 result 值,也就是 SpecSize。 在 AT_MOST 和 EXACTLY 模式下,都返回 SpecSize 这个值,即 View 在这两种模式下的测量 宽和高直接取决于 SpecSize。
对于一个直接继承自 View 的自定义 View 来说,它的 wrap_content 和 match_parent 属性的效果是一样的。因此如果要实现自定义 View 的 wrap_content,则要重写 onMeasure 方法,并对自定义 View 的 wrap_content 属性进行处理。
2、ViewGroup的measure过程
对于ViewGroup来说,除了完成自己的measure过程以外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个过程。和View不同的是,ViewGroup是一个抽象类,因此它没有重写View的onMeasure方法,但是它提供了一个叫measureChildren的方法。
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { final int size = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } } protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
measureChild的思想就是取出子元素的LayoutParams,然后再通过getChildMeasureSpec来创建子元素的MeasureSpec,接着将MeasureSpec直接传递给View的measure方法来进行测量。
ViewGroup并没有定义其测量的具体过程,这是因为ViewGroup是一个抽象类,其测量过程的onMeasure方法需要各个子类去具体实现,比如LinearLayout、RelativeLayout等。
为什么ViewGroup不像View一样对其onMeasure方法做统一的实现呢?那是因为不同的ViewGroup子类有不同的布局特性,这导致它们的测量细节各不相同,比如LinearLayout和RelativeLayout这两者的布局特性显然不同,因此ViewGroup无法做统一实现。
相关推荐
MeasureSpec是Android系统中用于布局管理的一个重要概念,它在处理View的尺寸计算时起到关键作用。MeasureSpec是由两个部分组成的:mode(模式)和size(大小)。在这个详解例子中,我们将深入探讨MeasureSpec的三种...
1. 当子View的LayoutParams的宽(高)采用具体的值(如100px)时且父容器的MeasureSpec为MeasureSpec.EXACTLY或者MeasureSpec.AT_MOST或者MeasureSpec.UNSPECIFIED时:系统返回给该子View的specMode就为MeasureSpec....
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } 搜索功能其实没写进demo里面,从项目里整理出来太麻烦了。...
1. **设置MeasureSpec**:MeasureSpec是一个组合了模式(MeasureSpec MODE)和大小(MeasureSpec SIZE)的32位整数。它包含了父视图对当前视图的尺寸限制。MeasureSpec有三种模式: - `MeasureSpec.EXACTLY`:父...
mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。 MeasureSpec.EXACTLY是精确尺寸, 当我们将控件的layout_width或layout_height指定为具体数值时如andorid ...
`onMeasure`方法用于计算控件的大小,它有三种测量模式:MeasureSpec.EXACTLY、MeasureSpec.AT_MOST和MeasureSpec.UNSPECIFIED。 1. **MeasureSpec.EXACTLY**:这是最常见的模式,表示父视图已经指定了确切的大小。...
通过`MeasureSpec`的`makeMeasureSpec`方法可以创建一个MeasureSpec,同时可以用`getMode`和`getSize`获取其specMode和specSize。 在View的`onMeasure`方法中,通常会调用`setMeasuredDimension`来设置View的测量...
int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { // 设置默认宽度 result = ...
MeasureSpec包含模式(MeasureSpec MODE)和大小(Size)两部分,模式分为EXACTLY(固定大小)、AT_MOST(最大不超过)和UNSPECIFIED(无限制)。我们需要根据MeasureSpec来计算视图的实际大小。 例如,如果要动态...
`onMeasure()`方法有两个参数:`MeasureSpec`,它们分别代表父容器对View宽度和高度的要求。MeasureSpec包含两个部分:模式(Mode)和大小(Size)。模式可以是EXACTLY(表示必须精确到给定大小)、AT_MOST(表示不...
此方法接收两个参数,`MeasureSpec`对象,分别代表父视图对当前视图宽度和高度的要求。MeasureSpec包含一个模式(MODE)和一个大小(SIZE)。模式有三种:EXACTLY(精确)、AT_MOST(最大不超过)和UNSPECIFIED(未...
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.AT_MOST); for (int i = 0; i (); i++) { getChildAt(i).measure(childWidthMeasureSpec, childHeightMeasureSpec); } ...
在自定义View或ViewGroup时,需要根据父容器的MeasureSpec和自己的LayoutParams来计算自己的MeasureSpec。 结论 ---- 自定义View和ViewGroup是Android应用程序中非常重要的组件,它们都是Android UI组件树的基础。...
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize + statusBarHeight, MeasureSpec.EXACTLY); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (heightMode != MeasureSpec....
int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.EXACTLY: // 父视图指定了确切的大小,使用这个大小 result = ...
setMeasuredDimension(measureSpec(widthMeasureSpec), measureSpec(heightMeasureSpec)); } private int measureSpec(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); ...
webView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); webView.layout(0, 0, webView.getMeasuredWidth(), webView....
`MeasureSpec.getSize()`获取父视图指定的大小,而`MeasureSpec.makeMeasureSpec()`则用于创建一个MeasureSpec对象,用于子视图的测量。 7. **测量过程**: `width`和`height`被设置为相等且基于屏幕宽度进行计算,...
`onMeasure()`方法接收两个参数:`MeasureSpec`对象,分别代表父视图对当前视图宽度和高度的要求。 MeasureSpec包含两个部分:模式(Mode)和大小(Size)。模式分为三种: 1. `EXACTLY`:父视图已经确定了具体的...