RelativeLayout 测量过程(代码流水线)
来源:互联网 发布:淘宝店铺手机号码修改 编辑:程序博客网 时间:2024/05/18 02:49
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mDirtyHierarchy) { mDirtyHierarchy = false; sortChildren(); } // 记录我们已知的尺寸; /** View的measure方法里对绘制过程做了一个优化,如果我们或者我们的子View没有要求强制刷新, 而父View给子View的传入值也没有变化(也就是说子View的位置没变化),就不会做无谓的measure。 RelativeLayout要做两次measure,而在做横向的测量时,纵向的测量结果尚未完成,只好暂时使用myHeight传入子View系统 假如子View的Height不等于(设置了margin)myHeight的高度, 那么measure中上面代码所做得优化将不起作用,这一过程将进一步影响RelativeLayout的绘制性能。 优化 如果可以,尽量使用padding代替margin。 **/ int myWidth = -1; int myHeight = -1; int width = 0; int height = 0; //得到模式 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); //得到宽高 final int widthSize = MeasureSpec.getSize(widthMeasureSpec); final int heightSize = MeasureSpec.getSize(heightMeasureSpec); // Record our dimensions if they are known; // 记录我们已知的尺寸; if (widthMode != MeasureSpec.UNSPECIFIED) { myWidth = widthSize; } if (heightMode != MeasureSpec.UNSPECIFIED) { myHeight = heightSize; } //模式 if (widthMode == MeasureSpec.EXACTLY) { width = myWidth; } if (heightMode == MeasureSpec.EXACTLY) { height = myHeight; } View ignore = null; int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; final boolean horizontalGravity = gravity != Gravity.START && gravity != 0; gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK; final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0; int left = Integer.MAX_VALUE; int top = Integer.MAX_VALUE; int right = Integer.MIN_VALUE; int bottom = Integer.MIN_VALUE; boolean offsetHorizontalAxis = false; boolean offsetVerticalAxis = false; if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) { ignore = findViewById(mIgnoreGravity); } final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY; final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY; // We need to know our size for doing the correct computation of children positioning in RTL // mode but there is no practical way to get it instead of running the code below. // So, instead of running the code twice, we just set the width to a "default display width" // before the computation and then, as a last pass, we will update their real position with // an offset equals to "DEFAULT_WIDTH - width". /*** 我们需要知道我们的尺寸,以便正确计算儿童的位置,在 RTL(从右到左)的布局镜面反射模式 但是没有实际的方法来获得它,而不是运行下面的代码。 因此,我们不是将代码运行两次,而是将宽度设置为“默认显示宽度”。在计算之前,然后作为最后一个通过,我们会更新他们的真实位置 一个偏移量等于 "DEFAULT_WIDTH - width". **/ final int layoutDirection = getLayoutDirection(); if (isLayoutRtl() && myWidth == -1) { myWidth = DEFAULT_WIDTH; } //水平方向的测量 孩子 View[] views = mSortedHorizontalChildren; int count = views.length; for (int i = 0; i < count; i++) { View child = views[i]; if (child.getVisibility() != GONE) {//只测量非gone的 //孩子的参数 LayoutParams params = (LayoutParams) child.getLayoutParams(); //孩子参数规则 int[] rules = params.getRules(layoutDirection); /** 尽可能的根据水平方向上的rules给child的childParams的mLeft和mRight设置值 根据理由: (1)view隔壁是否有其他view (2)view是否对齐 alignWithParent 根据孩子自己的布局参数,得到rules,给child的childParams的mLeft和mRight设置值 如果,值为VALUE_NOT_SET,则表示这个方向上一个rule都没有,并且值需要根据其他约束推断。 (在positionChildVertical()方法中被推断) 计算得到的数值 后续的步骤中还有可能被调整! 注意的是child的属性优先级的问题。在applyHorizontalSizeRules() (注意!这里限定在applyHorizontalSizeRules()方法中!)如果同一方向上有多个rules, 那么在applyHorizontalSizeRules()方法中最后判断的那个rule生效。 **/ applyHorizontalSizeRules(params, myWidth, rules); //测量宽高 measureChildHorizontal(child, params, myWidth, myHeight); //推断并设置mTop,mBottom中被设置为VALUE_NOT_SET的变量。 if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) { offsetHorizontalAxis = true; } } } views = mSortedVerticalChildren; count = views.length; final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; //竖直方向 测量 for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams params = (LayoutParams) child.getLayoutParams(); applyVerticalSizeRules(params, myHeight, child.getBaseline()); measureChild(child, params, myWidth, myHeight); if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) { offsetVerticalAxis = true; } if (isWrapContentWidth) { if (isLayoutRtl()) { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { width = Math.max(width, myWidth - params.mLeft); } else { width = Math.max(width, myWidth - params.mLeft - params.leftMargin); } } else { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { width = Math.max(width, params.mRight); } else { width = Math.max(width, params.mRight + params.rightMargin); } } } if (isWrapContentHeight) { if (targetSdkVersion < Build.VERSION_CODES.KITKAT) { height = Math.max(height, params.mBottom); } else { height = Math.max(height, params.mBottom + params.bottomMargin); } } if (child != ignore || verticalGravity) { left = Math.min(left, params.mLeft - params.leftMargin); top = Math.min(top, params.mTop - params.topMargin); } if (child != ignore || horizontalGravity) { right = Math.max(right, params.mRight + params.rightMargin); bottom = Math.max(bottom, params.mBottom + params.bottomMargin); } } } // Use the top-start-most laid out view as the baseline. RTL offsets are // applied later, so we can use the left-most edge as the starting edge. View baselineView = null; LayoutParams baselineParams = null; for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams childParams = (LayoutParams) child.getLayoutParams(); if (baselineView == null || baselineParams == null || compareLayoutPosition(childParams, baselineParams) < 0) { baselineView = child; baselineParams = childParams; } } } mBaselineView = baselineView; if (isWrapContentWidth) { // Width already has left padding in it since it was calculated by looking at // the right of each child view width += mPaddingRight; if (mLayoutParams != null && mLayoutParams.width >= 0) { width = Math.max(width, mLayoutParams.width); } width = Math.max(width, getSuggestedMinimumWidth()); width = resolveSize(width, widthMeasureSpec); if (offsetHorizontalAxis) { for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) { centerHorizontal(child, params, width); } else if (rules[ALIGN_PARENT_RIGHT] != 0) { final int childWidth = child.getMeasuredWidth(); params.mLeft = width - mPaddingRight - childWidth; params.mRight = params.mLeft + childWidth; } } } } } if (isWrapContentHeight) { // Height already has top padding in it since it was calculated by looking at // the bottom of each child view height += mPaddingBottom; if (mLayoutParams != null && mLayoutParams.height >= 0) { height = Math.max(height, mLayoutParams.height); } height = Math.max(height, getSuggestedMinimumHeight()); height = resolveSize(height, heightMeasureSpec); if (offsetVerticalAxis) { for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) { centerVertical(child, params, height); } else if (rules[ALIGN_PARENT_BOTTOM] != 0) { final int childHeight = child.getMeasuredHeight(); params.mTop = height - mPaddingBottom - childHeight; params.mBottom = params.mTop + childHeight; } } } } } if (horizontalGravity || verticalGravity) { final Rect selfBounds = mSelfBounds; selfBounds.set(mPaddingLeft, mPaddingTop, width - mPaddingRight, height - mPaddingBottom); final Rect contentBounds = mContentBounds; Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds, layoutDirection); final int horizontalOffset = contentBounds.left - left; final int verticalOffset = contentBounds.top - top; if (horizontalOffset != 0 || verticalOffset != 0) { for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE && child != ignore) { final LayoutParams params = (LayoutParams) child.getLayoutParams(); if (horizontalGravity) { params.mLeft += horizontalOffset; params.mRight += horizontalOffset; } if (verticalGravity) { params.mTop += verticalOffset; params.mBottom += verticalOffset; } } } } } if (isLayoutRtl()) { final int offsetWidth = myWidth - width; for (int i = 0; i < count; i++) { final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams params = (LayoutParams) child.getLayoutParams(); params.mLeft -= offsetWidth; params.mRight -= offsetWidth; } } } setMeasuredDimension(width, height); }
/*** 尽可能的根据水平方向上的rules给child的childParams的mLeft和mRight设置值。 **/ private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) { RelativeLayout.LayoutParams anchorParams; // VALUE_NOT_SET indicates a "soft requirement" in that direction. For example: // left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it // wants to the right // left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it // wants to the left // left=10, right=20 means the left and right ends are both fixed /** value_not_set表示“软要求”在那个方向 left=10, right=VALUE_NOT_SET 的意思,控件开始于10,可以往右边拓展延伸 **/ childParams.mLeft = VALUE_NOT_SET; childParams.mRight = VALUE_NOT_SET; //右边是否存在view anchorParams = getRelatedViewParams(rules, LEFT_OF); if (anchorParams != null) {//当前view 有related view;anchorParams 是相关view的参数 //计算得到本view的 mRight childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin + childParams.rightMargin); } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {//右边不存在view //根据父亲相关参数,得到 mRight if (myWidth >= 0) { childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; } } //同理 左边是否存在控件 anchorParams = getRelatedViewParams(rules, RIGHT_OF); if (anchorParams != null) { childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin + childParams.leftMargin); } else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) { childParams.mLeft = mPaddingLeft + childParams.leftMargin; } anchorParams = getRelatedViewParams(rules, ALIGN_LEFT); if (anchorParams != null) { childParams.mLeft = anchorParams.mLeft + childParams.leftMargin; } else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) { childParams.mLeft = mPaddingLeft + childParams.leftMargin; } anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT); if (anchorParams != null) { childParams.mRight = anchorParams.mRight - childParams.rightMargin; } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) { if (myWidth >= 0) { childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; } } if (0 != rules[ALIGN_PARENT_LEFT]) { childParams.mLeft = mPaddingLeft + childParams.leftMargin; } if (0 != rules[ALIGN_PARENT_RIGHT]) { if (myWidth >= 0) { childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin; } } } private void applyVerticalSizeRules(LayoutParams childParams, int myHeight, int myBaseline) { final int[] rules = childParams.getRules(); // Baseline alignment overrides any explicitly specified top or bottom. int baselineOffset = getRelatedViewBaselineOffset(rules); if (baselineOffset != -1) { if (myBaseline != -1) { baselineOffset -= myBaseline; } childParams.mTop = baselineOffset; childParams.mBottom = VALUE_NOT_SET; return; } RelativeLayout.LayoutParams anchorParams; childParams.mTop = VALUE_NOT_SET; childParams.mBottom = VALUE_NOT_SET; anchorParams = getRelatedViewParams(rules, ABOVE); if (anchorParams != null) { childParams.mBottom = anchorParams.mTop - (anchorParams.topMargin + childParams.bottomMargin); } else if (childParams.alignWithParent && rules[ABOVE] != 0) { if (myHeight >= 0) { childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin; } } anchorParams = getRelatedViewParams(rules, BELOW); if (anchorParams != null) { childParams.mTop = anchorParams.mBottom + (anchorParams.bottomMargin + childParams.topMargin); } else if (childParams.alignWithParent && rules[BELOW] != 0) { childParams.mTop = mPaddingTop + childParams.topMargin; } anchorParams = getRelatedViewParams(rules, ALIGN_TOP); if (anchorParams != null) { childParams.mTop = anchorParams.mTop + childParams.topMargin; } else if (childParams.alignWithParent && rules[ALIGN_TOP] != 0) { childParams.mTop = mPaddingTop + childParams.topMargin; } anchorParams = getRelatedViewParams(rules, ALIGN_BOTTOM); if (anchorParams != null) { childParams.mBottom = anchorParams.mBottom - childParams.bottomMargin; } else if (childParams.alignWithParent && rules[ALIGN_BOTTOM] != 0) { if (myHeight >= 0) { childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin; } } if (0 != rules[ALIGN_PARENT_TOP]) { childParams.mTop = mPaddingTop + childParams.topMargin; } if (0 != rules[ALIGN_PARENT_BOTTOM]) { if (myHeight >= 0) { childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin; } } }
【view的测量优化依据】
阅读全文
0 0
- RelativeLayout 测量过程(代码流水线)
- FrameLayout 测量过程(代码流水线)
- ARM7的三级流水线过程
- ARM7的三级流水线过程
- ARM7的三级流水线过程
- ARM7的三级流水线过程
- LinearLayout测量过程疑问
- LinearLayout测量过程分析
- Android View 测量过程
- 什么是流水线友好的代码?
- 什么是流水线友好的代码?
- 代码布局relativeLayout
- RelativeLayout代码布局
- 代码布局relativeLayout
- 代码中布局relativelayout
- 代码布局relativeLayout
- RelativeLayout 代码控制居中
- 代码实现 RelativeLayout布局
- iOS 循环引用问题解决方案
- 给 Java 初学者的学习路线建议
- 手机响应式布局rem和头部设置
- 枚举理解
- 网站代码一定要精简,有利于优化
- RelativeLayout 测量过程(代码流水线)
- 行程分析,连通域分析
- SpringBoot异常处理
- 福州大学acm Problem 2207 以撒的结合
- Android intent机制
- 解释一下关系数据库的第一第二第三范式?
- 关于synchronized的Monitor Object机制的研究
- 非入侵式脑机接口的两个应用
- 【水题】CodeForces