[关闭]
@RitcheeQinG 2020-04-26T02:55:34.000000Z 字数 9318 阅读 264

RelativeLayout源码分析(1)(发布版)

Android


过去自己记录的内容归档,内容较老,仅供参考

onMeasure

问题:

  1. RelativeLayout的child是不是无论如何都不可能超出parent?即使固定高度,再设置clipChildren和clipPadding?
  2. RelativeLayout的child是不是要绘制两遍?两次的区别在哪
  3. RelativeLayout因为什么导致了child超不出范围?
  4. 为什么wrap_content的情况下设置align会直接让其范围跑到屏幕边上?
  1. /**
  2. * Measure specification mode: The parent has not imposed any constraint
  3. * on the child. It can be whatever size it wants.
  4. */
  5. public static final int UNSPECIFIED = 0 << MODE_SHIFT;
  6. /**
  7. * Measure specification mode: The parent has determined an exact size
  8. * for the child. The child is going to be given those bounds regardless
  9. * of how big it wants to be.
  10. */
  11. public static final int EXACTLY = 1 << MODE_SHIFT;
  12. /**
  13. * Measure specification mode: The child can be as large as it wants up
  14. * to the specified size.
  15. */
  16. public static final int AT_MOST = 2 << MODE_SHIFT;
  1. UNSPECIFIED: parent没给child加任何限制,按照child申请的大小来
  2. EXACTLY: parent给child定好了大小,就按这么大,一般代表写死值或者match
  3. AT_MOST: 最大能大到一个精确数值,一般代表wrap_content
  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. // ...
  4. int myWidth = -1;
  5. int myHeight = -1;
  6. int width = 0;
  7. int height = 0;
  8. final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  9. final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  10. final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  11. final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  12. // Record our dimensions if they are known;
  13. // 如果是unspecified,那就是-1了,而这个-1会让其子view都是unspecified
  14. if (widthMode != MeasureSpec.UNSPECIFIED) {
  15. myWidth = widthSize;
  16. }
  17. if (heightMode != MeasureSpec.UNSPECIFIED) {
  18. myHeight = heightSize;
  19. }
  20. if (widthMode == MeasureSpec.EXACTLY) {
  21. width = myWidth;
  22. }
  23. if (heightMode == MeasureSpec.EXACTLY) {
  24. height = myHeight;
  25. }
  26. // ...
  27. }
  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. // ...
  4. for (int i = 0; i < count; i++) {
  5. View child = views[i];
  6. if (child.getVisibility() != GONE) {
  7. LayoutParams params = (LayoutParams) child.getLayoutParams();
  8. int[] rules = params.getRules(layoutDirection);
  9. // 基本上是在处理child和其周围相关child的关系,重新计算其layoutParams
  10. applyHorizontalSizeRules(params, myWidth, rules);
  11. measureChildHorizontal(child, params, myWidth, myHeight);
  12. if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
  13. offsetHorizontalAxis = true;
  14. }
  15. }
  16. }
  17. // ...
  18. }
  1. private void measureChildHorizontal(
  2. View child, LayoutParams params, int myWidth, int myHeight) {
  3. // myWidth和myHeight是RelativeLayout的,如果是unspecific,那就是-1
  4. // params是child自己的
  5. // widthMeasureSpec在这个下面这个方法里就算是计算完成了,但heightMeasureSpec还要在下面算
  6. final int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft, params.mRight, params.width, params.leftMargin, params.rightMargin, mPaddingLeft, mPaddingRight, myWidth);
  7. final int childHeightMeasureSpec;
  8. if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
  9. // relativeLayout is unspecified, and version > 17
  10. if (params.height >= 0) {
  11. // 众所周知wrap_content和match_parent分别是-2和-1
  12. // 代表child有写死值的高度了
  13. childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
  14. params.height, MeasureSpec.EXACTLY);
  15. } else {
  16. // parent都不确定,child如果是wrap或者match肯定也确定不了
  17. childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  18. }
  19. } else {
  20. // at most or exactly
  21. final int maxHeight;
  22. if (mMeasureVerticalWithPaddingMargin) {
  23. // version >= 18
  24. // 0 或者 RL高度 - (topPadding, topMargin, bottomPadding, bottomMargin)里面的最大值
  25. maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom - params.topMargin - params.bottomMargin);
  26. } else {
  27. // 似乎不到18这里的maxHeight就不把padding margin算进去了
  28. maxHeight = Math.max(0, myHeight);
  29. }
  30. final int heightMode;
  31. // 意思是如果此RelativeLayout的值确定了,child就只有match_parent时能确认值就和parent一样,其他情况都要按at most判断(因为即使写死值也可能比parent大)
  32. if (params.height == LayoutParams.MATCH_PARENT) {
  33. heightMode = MeasureSpec.EXACTLY;
  34. } else {
  35. heightMode = MeasureSpec.AT_MOST;
  36. }
  37. childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, heightMode);
  38. }
  39. child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  40. }

总结一下这里的第一次绘制

width = getChildMeasureSpec, height = myHeight - padding - margin

  1. /**
  2. * @param childStart The left or top field of the child's layout params
  3. * @param childEnd The right or bottom field of the child's layout params
  4. * @param childSize The child's desired size (the width or height field of the child's layout params)
  5. * @param startMargin The left or top margin
  6. * @param endMargin The right or bottom margin
  7. * @param startPadding mPaddingLeft or mPaddingTop
  8. * @param endPadding mPaddingRight or mPaddingBottom
  9. * @param mySize The width or height of this view (the RelativeLayout)
  10. * @return MeasureSpec for the child
  11. */
  12. private int getChildMeasureSpec(int childStart, int childEnd, int childSize, int startMargin, int endMargin, int startPadding, int endPadding, int mySize) {
  13. int childSpecMode = 0;
  14. int childSpecSize = 0;
  15. final boolean isUnspecified = mySize < 0;
  16. if (isUnspecified && !mAllowBrokenMeasureSpecs) {
  17. // 先忽略unSpecified,总之child宽高只要有值就会是exactly
  18. }
  19. // Figure out start and end bounds.
  20. // 这个方法里并不会再给childStart和childEnd赋值,如果没有任何约束,那默认自然是在左上角
  21. int tempStart = childStart;
  22. int tempEnd = childEnd;
  23. // 从上面给params赋值的过程可以看到,这里的值如果是default value,存在几种情况
  24. // 1.约束自己的对象gone掉了或者不存在,而且没设置alignParentIfMissing
  25. // 2.压根就没有约束
  26. // If the view did not express a layout constraint for an edge, use
  27. // view's margins and our padding
  28. if (tempStart == VALUE_NOT_SET) {
  29. // 没有约束的情况下(在左上角),左边最大可以是padding + margin
  30. tempStart = startPadding + startMargin;
  31. }
  32. if (tempEnd == VALUE_NOT_SET) {
  33. // 没有约束的情况下,右边最大是RL的右边 - padding - margin
  34. tempEnd = mySize - endPadding - endMargin;
  35. }
  36. // child的width最大的可能就是 mySize - padding - margin
  37. // 那么假设margin < 0 ?
  38. // Figure out maximum size available to this view
  39. final int maxAvailable = tempEnd - tempStart;
  40. if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
  41. // Constraints fixed both edges, so child must be an exact size.
  42. // 如果都有值了,就会是需求的right - left的精确范围
  43. childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
  44. childSpecSize = Math.max(0, maxAvailable);
  45. } else {
  46. // 有至少一边没定下来
  47. if (childSize >= 0) {
  48. // width/height >= 0
  49. // Child wanted an exact size. Give as much as possible.
  50. childSpecMode = MeasureSpec.EXACTLY;
  51. if (maxAvailable >= 0) {
  52. // We have a maximum size in this dimension.
  53. childSpecSize = Math.min(maxAvailable, childSize);
  54. } else {
  55. // We can grow in this dimension.
  56. childSpecSize = childSize;
  57. }
  58. } else if (childSize == LayoutParams.MATCH_PARENT) {
  59. // Child wanted to be as big as possible. Give all available
  60. // space.
  61. childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
  62. childSpecSize = Math.max(0, maxAvailable);
  63. } else if (childSize == LayoutParams.WRAP_CONTENT) {
  64. // Child wants to wrap content. Use AT_MOST to communicate
  65. // available space if we know our max size.
  66. if (maxAvailable >= 0) {
  67. // We have a maximum size in this dimension.
  68. childSpecMode = MeasureSpec.AT_MOST;
  69. childSpecSize = maxAvailable;
  70. } else {
  71. // We can grow in this dimension. Child can be as big as it
  72. // wants.
  73. childSpecMode = MeasureSpec.UNSPECIFIED;
  74. childSpecSize = 0;
  75. }
  76. }
  77. }
  78. return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
  79. }
  1. private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
  2. RelativeLayout.LayoutParams anchorParams;
  3. // VALUE_NOT_SET indicates a "soft requirement" in that direction. For example:
  4. // left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it
  5. // wants to the right
  6. // left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it
  7. // wants to the left
  8. // left=10, right=20 means the left and right ends are both fixed
  9. childParams.mLeft = VALUE_NOT_SET; // defualt value
  10. childParams.mRight = VALUE_NOT_SET;
  11. // anchor是对方的,child是自己的
  12. // 这里的left of从下文来看应该是指child left of 对方
  13. anchorParams = getRelatedViewParams(rules, LEFT_OF);
  14. // anchorParams可能为空的情况:1.Gone 2.没有这个View
  15. if (anchorParams != null) {
  16. // 对方的右边 - 双方margin = child左边
  17. childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin + childParams.rightMargin);
  18. } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
  19. // layout_alignWithParentIfMissing + left of的view不存在or gone
  20. /* alignWithParent: When true, uese the parent as the anchor if the anchor doesn't exist or if the anchor's visibility is gone */
  21. if (myWidth >= 0) {
  22. childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
  23. }
  24. }
  25. // 如果啥都没标注,此时应该left还是not set
  26. anchorParams = getRelatedViewParams(rules, RIGHT_OF);
  27. if (anchorParams != null) {
  28. childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin + childParams.leftMargin);
  29. } else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) {
  30. childParams.mLeft = mPaddingLeft + childParams.leftMargin;
  31. }
  32. anchorParams = getRelatedViewParams(rules, ALIGN_LEFT);
  33. if (anchorParams != null) {
  34. // 对方的margin此时已经被加进left了吗?
  35. childParams.mLeft = anchorParams.mLeft + childParams.leftMargin;
  36. } else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) {
  37. childParams.mLeft = mPaddingLeft + childParams.leftMargin;
  38. }
  39. anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT);
  40. if (anchorParams != null) {
  41. childParams.mRight = anchorParams.mRight - childParams.rightMargin;
  42. } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
  43. if (myWidth >= 0) {
  44. childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
  45. }
  46. }
  47. if (0 != rules[ALIGN_PARENT_LEFT]) {
  48. childParams.mLeft = mPaddingLeft + childParams.leftMargin;
  49. }
  50. if (0 != rules[ALIGN_PARENT_RIGHT]) {
  51. if (myWidth >= 0) {
  52. childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
  53. }
  54. }
  55. // 判断的顺序: left of, right of, align left, align right, align parnent left, align parent left
  56. // 如果rules中什么都不包括,那么到了这里应该还是default value
  57. }

sort过程:

会按照依赖关系进行排序,需要先处理的会被排序在前面

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. // ...
  4. if (isWrapContentWidth) {
  5. // Width already has left padding in it since it was calculated by looking at
  6. // the right of each child view
  7. width += mPaddingRight;
  8. if (mLayoutParams != null && mLayoutParams.width >= 0) {
  9. width = Math.max(width, mLayoutParams.width);
  10. }
  11. width = Math.max(width, getSuggestedMinimumWidth());
  12. width = resolveSize(width, widthMeasureSpec);
  13. if (offsetHorizontalAxis) {
  14. for (int i = 0; i < count; i++) {
  15. final View child = views[i];
  16. if (child.getVisibility() != GONE) {
  17. final LayoutParams params = (LayoutParams) child.getLayoutParams();
  18. final int[] rules = params.getRules(layoutDirection);
  19. if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
  20. centerHorizontal(child, params, width);
  21. } else if (rules[ALIGN_PARENT_RIGHT] != 0) {
  22. final int childWidth = child.getMeasuredWidth();
  23. params.mLeft = width - mPaddingRight - childWidth;
  24. params.mRight = params.mLeft + childWidth;
  25. }
  26. }
  27. }
  28. }
  29. }
  30. // ...
  31. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注