View和ViewGroup 的measure过程
视图有3大流程,measure,layout,draw,即测量,布局和绘制.我们先分析第一个流程measure.
1.View 的measure过程
View 的measure过程是由其measure()来完成,这个方法是final类型的,也就是不能被之类重写,同时measure()会转调onMeasure(),所以我们暂时重点关注onMeasure()就可以了.实际我们在自定义一个视图控件的时候也是重写onMeasure方法.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}
上面的方法就是调用了setMeasuredDismension()来设置mMeasuredWidth和mMeasuredHeight,这2个变量会在View 的layout 流程和draw流程用到.但是在调用setMeasuredDismension 时它的参数是由getDefaultSize()来得到的.具体源码如下:
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;}protected int getSuggestedMinimumWidth() {return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());}
其中getDefaultSize就是根据View 的MeasureSpec和另一个参数size来获取返回值.
其中我们需要关注的是MeasureSpec.AT_MOST和MeasureSpec.EXACTLY2种模式,也就是都返回specSize.这个specSize也就是由由父容器的MeasureSpec和View自身的LayoutParams共同生成的View的MeasureSpec调用getsize得到的大小,可以理解为View
的测量之后得到的宽高大小.
上面另外一种模式MeasureSpec.UNSPECIFIED,是用来系统内部测量的.这种情况下返回值是size,也就是的getSuggestedMinimumWidth和getSuggestedMinimumHeight返回值大小.
对getSuggestedMinimumWidth()源码可以得出结论:如果View没有设置背景,View
的宽度就是android:minWidth的值,如果没有设置这个值就是0,如果设置了背景,就是android:minWidth和背景图标的宽度的较大值.
2.ViewGroup 的measure过程
由于measure不能被重写,而且ViewGroup没有重写onMeasure(),所以是通过其他方法来处理这个measure流程.实际是使用的measureChildren().
ViewGroup.java
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);}
上面的代码就是循环调用child view 的measure()方法,如果child view 也有child,那么就会递归执行这个measureChildren().
其中getChildMeasureSpec()之前已经笔记"View
MeasureSpec 和LayoutParams关系"里面分析过,这里就重复分析.
所以我们可以知道ViewGroup没有执行具体的测量过程,只是调用child view 的measure()方法.这是因为ViewGroup子类太多,不好统一处理.实际是各个子类去重写onMeasure来自己处理的.
本文详细解析了Android中View和ViewGroup的测量流程,包括measure过程中的关键方法如onMeasure()、setMeasuredDimension()等,并探讨了MeasureSpec的作用及其与LayoutParams的关系。
385

被折叠的 条评论
为什么被折叠?



