[关闭]
@RitcheeQinG 2020-03-23T08:27:09.000000Z 字数 4820 阅读 461

Android Clip属性效果简单研究

Android


本篇编辑时间在半年前,项目target API在26,安卓版本为15-27,半年过去想起来可以发布一下,仅供参考

clipChildren

这个属性得写在根布局,然后对直接子view似乎不会生效,得对子view的子view才能生效

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@color/filter_grey"
  6. android:clipChildren="false"
  7. android:clipToPadding="false"
  8. android:orientation="vertical">
  9. <RelativeLayout
  10. android:layout_width="150dp"
  11. android:layout_height="150dp"
  12. android:background="#4000FF00"
  13. android:orientation="vertical">
  14. <View
  15. android:id="@+id/view_blue"
  16. android:layout_width="50dp"
  17. android:layout_height="50dp"
  18. android:layout_marginLeft="200dp"
  19. android:layout_marginTop="200dp"
  20. android:background="#400000FF" />
  21. </RelativeLayout>
  22. </RelativeLayout>

image.png-5.9kB

把其中任何一个margin改成150:

image.png-5.2kB
再随便改一下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@color/filter_grey"
  6. android:clipChildren="false"
  7. android:clipToPadding="false"
  8. android:orientation="vertical">
  9. <RelativeLayout
  10. android:layout_width="150dp"
  11. android:layout_height="150dp"
  12. android:layout_centerInParent="true"
  13. android:background="#4000FF00"
  14. android:orientation="vertical">
  15. <View
  16. android:id="@+id/view_blue"
  17. android:layout_width="50dp"
  18. android:layout_height="50dp"
  19. android:layout_marginLeft="-20dp"
  20. android:layout_marginTop="-20dp"
  21. android:background="#400000FF" />
  22. </RelativeLayout>
  23. </RelativeLayout>

3
再随便改一下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@color/filter_grey"
  6. android:clipChildren="false"
  7. android:clipToPadding="false"
  8. android:orientation="vertical">
  9. <RelativeLayout
  10. android:layout_width="150dp"
  11. android:layout_height="150dp"
  12. android:layout_centerInParent="true"
  13. android:background="#4000FF00"
  14. android:orientation="vertical">
  15. <View
  16. android:id="@+id/view_blue"
  17. android:layout_width="match_parent"
  18. android:layout_height="match_parent"
  19. android:layout_marginLeft="-20dp"
  20. android:layout_marginRight="-20dp"
  21. android:layout_marginTop="-20dp"
  22. android:background="#400000FF" />
  23. </RelativeLayout>
  24. </RelativeLayout>

image.png-5.4kB
源码:

  1. private int getChildMeasureSpec(int childStart, int childEnd, int childSize, int startMargin, int endMargin, int startPadding, int endPadding, int mySize) {
  2. ...
  3. // Figure out start and end bounds.
  4. // 这个方法里并不会再给childStart和childEnd赋值,如果没有任何约束,那默认自然是在左上角
  5. int tempStart = childStart;
  6. int tempEnd = childEnd;
  7. // 从上面给params赋值的过程可以看到,这里的值如果是default value,存在几种情况
  8. // 1.约束自己的对象gone掉了或者不存在,而且没设置alignParentIfMissing
  9. // 2.压根就没有约束
  10. // If the view did not express a layout constraint for an edge, use
  11. // view's margins and our padding
  12. if (tempStart == VALUE_NOT_SET) {
  13. // 没有约束的情况下(在左上角),左边最大可以是padding + margin
  14. tempStart = startPadding + startMargin;
  15. }
  16. if (tempEnd == VALUE_NOT_SET) {
  17. // 没有约束的情况下,右边最大是RL的右边 - padding - margin
  18. tempEnd = mySize - endPadding - endMargin;
  19. }
  20. // child的width最大的可能就是 mySize - padding - margin
  21. // 那么假设margin < 0 ?
  22. // Figure out maximum size available to this view
  23. final int maxAvailable = tempEnd - tempStart;
  24. if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
  25. // Constraints fixed both edges, so child must be an exact size.
  26. // 如果都有值了,就会是需求的right - left的精确范围
  27. childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
  28. childSpecSize = Math.max(0, maxAvailable);
  29. } else {
  30. // 有至少一边没定下来
  31. if (childSize >= 0) {
  32. // width/height >= 0
  33. // Child wanted an exact size. Give as much as possible.
  34. childSpecMode = MeasureSpec.EXACTLY;
  35. if (maxAvailable >= 0) {
  36. // We have a maximum size in this dimension.
  37. childSpecSize = Math.min(maxAvailable, childSize);
  38. } else {
  39. // We can grow in this dimension.
  40. childSpecSize = childSize;
  41. }
  42. } else if (childSize == LayoutParams.MATCH_PARENT) {
  43. // Child wanted to be as big as possible. Give all available
  44. // space.
  45. childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
  46. childSpecSize = Math.max(0, maxAvailable);
  47. } else if (childSize == LayoutParams.WRAP_CONTENT) {
  48. // Child wants to wrap content. Use AT_MOST to communicate
  49. // available space if we know our max size.
  50. if (maxAvailable >= 0) {
  51. // We have a maximum size in this dimension.
  52. childSpecMode = MeasureSpec.AT_MOST;
  53. childSpecSize = maxAvailable;
  54. } else {
  55. // We can grow in this dimension. Child can be as big as it
  56. // wants.
  57. childSpecMode = MeasureSpec.UNSPECIFIED;
  58. childSpecSize = 0;
  59. }
  60. }
  61. }
  62. return MeasureSpec.makeMeasureSpec(childSpecSize, childSpecMode);
  63. }

关于ClipChildren的分析

从源码我们可以看到,分为这么几种情况:

  1. 两边都有约束,于是左右都有值:必定在RelativeLayout范围内
  2. 至少有一边没有约束,所以没有值:
    1. child设置了固定的width
      • maxAvailable >= 0 这种情况会取maxAvailable和width之间的最小值,所以可以看见由于设置margin,越靠近边缘,maxAvailable越小,图片越小,直到margin刚好等于RelativeLayout的宽时,child消失不见。
        注:这种情况下child不是被裁剪,而是被等比缩小,随便用一张图片设置imageView就能看出来
      • maxAvailable < 0 (这种情况即设置的margin比父RelativeLayout的宽/高还要大的情况),看源代码可知这里最终的size就等于child的width,所以能显示出来
    2. child设置了match_parent
      这种情况下全都按maxAvailable的值来计算child的宽高,所以我们能看到,在margin为负数时,设置match直接让child超过了parent范围(当然,是需要clipChildren的)
    3. child设置了wrap_content
      这里没搞太懂,不知道到底怎么样才算是wrap_content

clipToPadding

这个可以写在父布局,会生效

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注