@RitcheeQinG
2020-03-23T08:27:09.000000Z
字数 4820
阅读 461
Android
本篇编辑时间在半年前,项目target API在26,安卓版本为15-27,半年过去想起来可以发布一下,仅供参考
这个属性得写在根布局,然后对直接子view似乎不会生效,得对子view的子view才能生效
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/filter_grey"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<RelativeLayout
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#4000FF00"
android:orientation="vertical">
<View
android:id="@+id/view_blue"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="200dp"
android:layout_marginTop="200dp"
android:background="#400000FF" />
</RelativeLayout>
</RelativeLayout>
把其中任何一个margin改成150:
再随便改一下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/filter_grey"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<RelativeLayout
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerInParent="true"
android:background="#4000FF00"
android:orientation="vertical">
<View
android:id="@+id/view_blue"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="-20dp"
android:layout_marginTop="-20dp"
android:background="#400000FF" />
</RelativeLayout>
</RelativeLayout>
再随便改一下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/filter_grey"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<RelativeLayout
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerInParent="true"
android:background="#4000FF00"
android:orientation="vertical">
<View
android:id="@+id/view_blue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="-20dp"
android:layout_marginRight="-20dp"
android:layout_marginTop="-20dp"
android:background="#400000FF" />
</RelativeLayout>
</RelativeLayout>
源码:
private int getChildMeasureSpec(int childStart, int childEnd, int childSize, int startMargin, int endMargin, int startPadding, int endPadding, int mySize) {
...
// 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 padding
if (tempStart == VALUE_NOT_SET) {
// 没有约束的情况下(在左上角),左边最大可以是padding + margin
tempStart = startPadding + startMargin;
}
if (tempEnd == VALUE_NOT_SET) {
// 没有约束的情况下,右边最大是RL的右边 - padding - margin
tempEnd = mySize - endPadding - endMargin;
}
// child的width最大的可能就是 mySize - padding - margin
// 那么假设margin < 0 ?
// Figure out maximum size available to this view
final 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);
}
从源码我们可以看到,分为这么几种情况:
maxAvailable
>= 0 这种情况会取maxAvailable和width之间的最小值,所以可以看见由于设置margin,越靠近边缘,maxAvailable越小,图片越小,直到margin刚好等于RelativeLayout的宽时,child消失不见。 maxAvailable
< 0 (这种情况即设置的margin比父RelativeLayout的宽/高还要大的情况),看源代码可知这里最终的size就等于child的width,所以能显示出来这个可以写在父布局,会生效