@RitcheeQinG
2020-04-26T02:55:34.000000Z
字数 9318
阅读 317
Android
过去自己记录的内容归档,内容较老,仅供参考
/*** Measure specification mode: The parent has not imposed any constraint* on the child. It can be whatever size it wants.*/public static final int UNSPECIFIED = 0 << MODE_SHIFT;/*** Measure specification mode: The parent has determined an exact size* for the child. The child is going to be given those bounds regardless* of how big it wants to be.*/public static final int EXACTLY = 1 << MODE_SHIFT;/*** Measure specification mode: The child can be as large as it wants up* to the specified size.*/public static final int AT_MOST = 2 << MODE_SHIFT;
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// ...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;// 如果是unspecified,那就是-1了,而这个-1会让其子view都是unspecifiedif (widthMode != MeasureSpec.UNSPECIFIED) {myWidth = widthSize;}if (heightMode != MeasureSpec.UNSPECIFIED) {myHeight = heightSize;}if (widthMode == MeasureSpec.EXACTLY) {width = myWidth;}if (heightMode == MeasureSpec.EXACTLY) {height = myHeight;}// ...}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// ...for (int i = 0; i < count; i++) {View child = views[i];if (child.getVisibility() != GONE) {LayoutParams params = (LayoutParams) child.getLayoutParams();int[] rules = params.getRules(layoutDirection);// 基本上是在处理child和其周围相关child的关系,重新计算其layoutParamsapplyHorizontalSizeRules(params, myWidth, rules);measureChildHorizontal(child, params, myWidth, myHeight);if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {offsetHorizontalAxis = true;}}}// ...}
private void measureChildHorizontal(View child, LayoutParams params, int myWidth, int myHeight) {// myWidth和myHeight是RelativeLayout的,如果是unspecific,那就是-1// params是child自己的// widthMeasureSpec在这个下面这个方法里就算是计算完成了,但heightMeasureSpec还要在下面算final int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft, params.mRight, params.width, params.leftMargin, params.rightMargin, mPaddingLeft, mPaddingRight, myWidth);final int childHeightMeasureSpec;if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {// relativeLayout is unspecified, and version > 17if (params.height >= 0) {// 众所周知wrap_content和match_parent分别是-2和-1// 代表child有写死值的高度了childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY);} else {// parent都不确定,child如果是wrap或者match肯定也确定不了childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);}} else {// at most or exactlyfinal int maxHeight;if (mMeasureVerticalWithPaddingMargin) {// version >= 18// 0 或者 RL高度 - (topPadding, topMargin, bottomPadding, bottomMargin)里面的最大值maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom - params.topMargin - params.bottomMargin);} else {// 似乎不到18这里的maxHeight就不把padding margin算进去了maxHeight = Math.max(0, myHeight);}final int heightMode;// 意思是如果此RelativeLayout的值确定了,child就只有match_parent时能确认值就和parent一样,其他情况都要按at most判断(因为即使写死值也可能比parent大)if (params.height == LayoutParams.MATCH_PARENT) {heightMode = MeasureSpec.EXACTLY;} else {heightMode = MeasureSpec.AT_MOST;}childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, heightMode);}child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}
总结一下这里的第一次绘制
width = getChildMeasureSpec, height = myHeight - padding - margin
/*** @param childStart The left or top field of the child's layout params* @param childEnd The right or bottom field of the child's layout params* @param childSize The child's desired size (the width or height field of the child's layout params)* @param startMargin The left or top margin* @param endMargin The right or bottom margin* @param startPadding mPaddingLeft or mPaddingTop* @param endPadding mPaddingRight or mPaddingBottom* @param mySize The width or height of this view (the RelativeLayout)* @return MeasureSpec for the child*/private int getChildMeasureSpec(int childStart, int childEnd, int childSize, int startMargin, int endMargin, int startPadding, int endPadding, int mySize) {int childSpecMode = 0;int childSpecSize = 0;final boolean isUnspecified = mySize < 0;if (isUnspecified && !mAllowBrokenMeasureSpecs) {// 先忽略unSpecified,总之child宽高只要有值就会是exactly}// Figure out start and end bounds.// 这个方法里并不会再给childStart和childEnd赋值,如果没有任何约束,那默认自然是在左上角int tempStart = childStart;int tempEnd = childEnd;// 从上面给params赋值的过程可以看到,这里的值如果是default value,存在几种情况// 1.约束自己的对象gone掉了或者不存在,而且没设置alignParentIfMissing// 2.压根就没有约束// If the view did not express a layout constraint for an edge, use// view's margins and our paddingif (tempStart == VALUE_NOT_SET) {// 没有约束的情况下(在左上角),左边最大可以是padding + margintempStart = startPadding + startMargin;}if (tempEnd == VALUE_NOT_SET) {// 没有约束的情况下,右边最大是RL的右边 - padding - margintempEnd = mySize - endPadding - endMargin;}// child的width最大的可能就是 mySize - padding - margin// 那么假设margin < 0 ?// Figure out maximum size available to this viewfinal int maxAvailable = tempEnd - tempStart;if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {// Constraints fixed both edges, so child must be an exact size.// 如果都有值了,就会是需求的right - left的精确范围childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;childSpecSize = Math.max(0, maxAvailable);} else {// 有至少一边没定下来if (childSize >= 0) {// width/height >= 0// Child wanted an exact size. Give as much as possible.childSpecMode = MeasureSpec.EXACTLY;if (maxAvailable >= 0) {// We have a maximum size in this dimension.childSpecSize = Math.min(maxAvailable, childSize);} else {// We can grow in this dimension.childSpecSize = childSize;}} else if (childSize == LayoutParams.MATCH_PARENT) {// Child wanted to be as big as possible. Give all available// space.childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;childSpecSize = Math.max(0, maxAvailable);} else if (childSize == LayoutParams.WRAP_CONTENT) {// Child wants to wrap content. Use AT_MOST to communicate// available space if we know our max size.if (maxAvailable >= 0) {// We have a maximum size in this dimension.childSpecMode = MeasureSpec.AT_MOST;childSpecSize = maxAvailable;} else {// We can grow in this dimension. Child can be as big as it// wants.childSpecMode = MeasureSpec.UNSPECIFIED;childSpecSize = 0;}}}return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);}
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 fixedchildParams.mLeft = VALUE_NOT_SET; // defualt valuechildParams.mRight = VALUE_NOT_SET;// anchor是对方的,child是自己的// 这里的left of从下文来看应该是指child left of 对方anchorParams = getRelatedViewParams(rules, LEFT_OF);// anchorParams可能为空的情况:1.Gone 2.没有这个Viewif (anchorParams != null) {// 对方的右边 - 双方margin = child左边childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin + childParams.rightMargin);} else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {// layout_alignWithParentIfMissing + left of的view不存在or gone/* alignWithParent: When true, uese the parent as the anchor if the anchor doesn't exist or if the anchor's visibility is gone */if (myWidth >= 0) {childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;}}// 如果啥都没标注,此时应该left还是not setanchorParams = 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) {// 对方的margin此时已经被加进left了吗?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;}}// 判断的顺序: left of, right of, align left, align right, align parnent left, align parent left// 如果rules中什么都不包括,那么到了这里应该还是default value}
sort过程:
会按照依赖关系进行排序,需要先处理的会被排序在前面
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// ...if (isWrapContentWidth) {// Width already has left padding in it since it was calculated by looking at// the right of each child viewwidth += 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;}}}}}// ...}