Android中View绘制过程(四) performMeasure
来源:互联网 发布:怎么查看网络是否稳定 编辑:程序博客网 时间:2024/06/05 17:12
performTraversals()功能和名字一致,开始遍历。
方法中首先开始测量,
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); try { mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
调用DecorView的measure方法,之后Decor会遍历调用自己的ChildView的measure,ClidView如果是ViewGroup将遍历自己的ChidView,以此遍历整个ViewTree。
DecorView是一个FramLayout,也就是个ViewGroup,分析DercorView就相当于分析了其他的ViewGroup了,这里的参数childWidthMeasureSpec即屏幕的宽,因为的decorView,这里固定为屏幕的宽高作为参数,如果是其他的ViewGroup则是上一级测量之后,给它的空间了。
ViewGroup中没有measur方法,父类View中有,调用onMeasure,这个ViewGroup中也没有,只能再看当前的FrameLayout了。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); final boolean measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; mMatchParentChildren.clear(); int maxHeight = 0; int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (mMeasureAllChildren || child.getVisibility() != GONE) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, child.getMeasuredState()); if (measureMatchParentChildren) { if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) { mMatchParentChildren.add(child); } } } } // Account for padding too maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground(); maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground(); // Check against our minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); // Check against our foreground's minimum height and width final Drawable drawable = getForeground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); count = mMatchParentChildren.size(); if (count > 1) { for (int i = 0; i < count; i++) { final View child = mMatchParentChildren.get(i); final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec; if (lp.width == LayoutParams.MATCH_PARENT) { final int width = Math.max(0, getMeasuredWidth() - getPaddingLeftWithForeground() - getPaddingRightWithForeground() - lp.leftMargin - lp.rightMargin); childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY); } else { childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeftWithForeground() + getPaddingRightWithForeground() + lp.leftMargin + lp.rightMargin, lp.width); } final int childHeightMeasureSpec; if (lp.height == LayoutParams.MATCH_PARENT) { final int height = Math.max(0, getMeasuredHeight() - getPaddingTopWithForeground() - getPaddingBottomWithForeground() - lp.topMargin - lp.bottomMargin); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY); } else { childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTopWithForeground() + getPaddingBottomWithForeground() + lp.topMargin + lp.bottomMargin, lp.height); } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } }
在遍历ChildView的时候终于会调用getChildMeasureSpec这个方法,如下
public static int getChildMeasureSpec(int spec, int padding, int childDimension) { int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }
在这个方法中分别对,在layout中设置的layout_width,layout_height等作出不同的取值,当MATCH_PARENT=-1,WRAP_CONTENT=-2,和具体数值时的取值。
例如
1)当父ViewGroup节点测量时EXACTLY,如果layout设置的值是>0,则直接使用。Mode也是EXACTLY
2)当父ViewGroup节点测量时EXACTLY,如果layout设置的值MATCH_PARENT,那么测量值就是int size = Math.max(0, specSize - padding);
getChildMeasureSpec()这个方法对所有情况进行了讨论。 这也就是为什么设置MATCH_PARENT,WRAP_CONTENT,系统能知道大小的原因。
因为有很多其他的VIewGroup ,LineraLayout,RelativeLayout,等等,测量的方式也是不一样的。
这个FramLayout 就遍历了自己的Child,找到最宽的宽度,和最高的高度,作为宽高传到下一级测量。这个符合我们平时使用FrameLayout的现象,如果是WrapContent。DecorVIew传进来值是全屏的,那就是全屏的了。
将自己测量的自己的值遍历传递到下一级,继续测量。
其他的各有自己的测量方法,View不用遍历自己的子View,测量就是自己的大小。例如TextView,ImageView自己的onMeasure会根据情况来setMeasuredDimension()。LinerLayout,RelativeLayout也有自己的遍历计算方式。具体问题要具体分析了。
这样测量下来之后,DecorView根节点下的View全部测量完毕,各个View的变量,mMeasuredWidth,mMeasuredHeight都是已知的了。
下一步就该找找他们的放置的位置了
下一篇performLayout()。
- Android中View绘制过程(四) performMeasure
- Android中view绘制过程
- Android中View绘制过程(一) decorView绘制
- Android中View绘制过程(三) setContentView()到performTraversals()
- Android中View绘制过程(五) performlayout
- Android中View绘制过程(六) performDraw
- Android中View的绘制过程
- android中View绘制过程分析
- Android中View的绘制过程
- Android中View的绘制过程
- Android中View的绘制过程
- Android中View的绘制过程
- Android View绘制过程
- Android View绘制过程
- Android View绘制过程
- Android View绘制过程
- Android View绘制过程
- Android View绘制过程
- LDA-inference
- 【APICloud】Android数字证书概述
- 2- python 流程控制篇
- leetcode-625. Minimum Factorization
- AMD、CMD、webpack理解
- Android中View绘制过程(四) performMeasure
- http切换到https的tomcat配置
- Oracle中的闪回
- leetcode624: Maximum Distance in Arrays
- 3-python 函数篇
- javascript中的数值转换与逻辑非的比较
- jsp页面的前进刷新后退
- 用好React,你必须要知道的事情
- HBase性能优化方法总结(三):读表操作