Reputation: 937
The following two layout files produce different results:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<View
android:id="@+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/next_box" />
<View
android:id="@+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
/>
</RelativeLayout>
</LinearLayout>
Result:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<View
android:id="@+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
/>
<View
android:id="@+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
android:layout_toRightOf="@+id/box"
/>
</RelativeLayout>
</LinearLayout>
Result:
Both layouts are trying to describe the same constraints. Namely, the red rectangle should touch the left edge of the parent, the blue rectangle should touch the right edge of the parent, and they should appear next to each other horizontally. The only difference is whether you specify the "next to" constraint on the red rectangle or the blue rectangle. I figured out the reason which has to do with the measure resolution order generated by forming a dependency graph of the constraints, but I only figured it out through reading RelativeLayout's source code, and I couldn't find any documentation / notes regarding this behavior. Since RelativeLayout must be a commonly used layout component, is there a more intuitive explanation for this behavior, or is there some part of documentation that I am missing?
Upvotes: 2
Views: 381
Reputation: 2048
All this parameters defined in: android.widget.RelativeLayout
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
childParams.mLeft = VALUE_NOT_SET;
childParams.mRight = VALUE_NOT_SET;
anchorParams = getRelatedViewParams(rules, LEFT_OF);
if (anchorParams != null) {
childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
childParams.rightMargin);
} else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
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;
}
}
}
The view left and right edges ( childParams.mLeft, childParams.mRight) calculations based on anchor view parameters (anchorParams). From this code childParams.mRight edge of the view defined by LEFT_OF (android:layout_toLeftOf) can be recalculated by ALIGN_RIGHT (android:layout_alignRight) or ALIGN_PARENT_RIGHT (android:layout_alignParentRight). Here is explanation why 0-width red view become more than 0.
<View
android:id="@+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/next_box"/>
Right edge of this view defined by LEFT_OF:
childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
childParams.rightMargin);
In this case anchor view is:
<View
android:id="@+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
/>
the left edge of this view 60dp from the right side of the screen margings not defined => childParams.mRight = screen_width - 60dp
Left edge of this view defined by ALIGN_PARENT_LEFT:
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
the left edge of this view left edge of anchor view is 0 because android:layout_alignParentLeft="true" and margins not defined => childParams.mLeft = 0
the same calculation can be done for the second example: childParams.mRight = screen_width childParams.mLeft = 0
Upvotes: 1
Reputation: 4514
Although both seem to describe the same constraints, they actually don't. The difference is that one says, red must sit next to blue, while the other says blue must sit next to red. One means that where ever red goes blue must follow, the other says, where ever blue goes red must follow, and they both want to go to different places.
In the first instance, red box depends on the blue box, so the blue box gets constructed first. The blue box has a width of 60dp, so a 60dp blue box is constructed first and aligned right. Then comes the red box, which has a constraint to sit next to the blue box. Width 0 is ignore because it needs to sit next to 60dp blue and align left.
In the second instance, blue box depends on the red box, so the red box gets constructed first. The red box says it wants 0dp and align left, so it can't be seen. Then comes the blue box which needs to sit next to invisible red and align right, thus occupying the entire space, its width ignored.
Hope this makes sense :)
Upvotes: 4