Fix gravity handling in CoordinatorLayout
When a child without behavior or anchor has only one axis specified as
its layout_gravity, CoL was centering the child for the other axis.
Bug: 33655774
Test: CoordinatorLayoutTest#testLayoutChildren on 9, 15, 19, 25
Change-Id: Ie56afa62491251b01355b269c9f4c0d79658da4d
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 1f570b6..e0ec883 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -1171,11 +1171,18 @@
}
/**
- * Return the given gravity value or the default if the passed value is NO_GRAVITY.
- * This should be used for children that are not anchored to another view or a keyline.
+ * Return the given gravity value, but if either or both of the axes doesn't have any gravity
+ * specified, the default value (start or top) is specified. This should be used for children
+ * that are not anchored to another view or a keyline.
*/
private static int resolveGravity(int gravity) {
- return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
+ if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+ gravity |= GravityCompat.START;
+ }
+ if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+ gravity |= Gravity.TOP;
+ }
+ return gravity;
}
/**
@@ -2560,8 +2567,10 @@
/**
* A {@link Gravity} value describing how this child view should lay out.
- * If an {@link #setAnchorId(int) anchor} is also specified, the gravity describes
- * how this child view should be positioned relative to its anchored position.
+ * If either or both of the axes are not specified, they are treated by CoordinatorLayout
+ * as {@link Gravity#TOP} or {@link GravityCompat#START}. If an
+ * {@link #setAnchorId(int) anchor} is also specified, the gravity describes how this child
+ * view should be positioned relative to its anchored position.
*/
public int gravity = Gravity.NO_GRAVITY;
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index f8e4f99..73ad193 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -45,6 +45,7 @@
import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SdkSuppress;
+import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.WindowInsetsCompat;
import android.view.Gravity;
@@ -129,6 +130,58 @@
}
@Test
+ public void testLayoutChildren() throws Throwable {
+ final Instrumentation instrumentation = getInstrumentation();
+ final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+ final View view = new View(col.getContext());
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ col.addView(view, 100, 100);
+ }
+ });
+ instrumentation.waitForIdleSync();
+ int horizontallyCentered = (col.getWidth() - view.getWidth()) / 2;
+ int end = col.getWidth() - view.getWidth();
+ int verticallyCentered = (col.getHeight() - view.getHeight()) / 2;
+ int bottom = col.getHeight() - view.getHeight();
+ final int[][] testCases = {
+ // gravity, expected left, expected top
+ {Gravity.NO_GRAVITY, 0, 0},
+ {Gravity.LEFT, 0, 0},
+ {GravityCompat.START, 0, 0},
+ {Gravity.TOP, 0, 0},
+ {Gravity.CENTER, horizontallyCentered, verticallyCentered},
+ {Gravity.CENTER_HORIZONTAL, horizontallyCentered, 0},
+ {Gravity.CENTER_VERTICAL, 0, verticallyCentered},
+ {Gravity.RIGHT, end, 0},
+ {GravityCompat.END, end, 0},
+ {Gravity.BOTTOM, 0, bottom},
+ {Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, horizontallyCentered, bottom},
+ {Gravity.RIGHT | Gravity.CENTER_VERTICAL, end, verticallyCentered},
+ };
+ for (final int[] testCase : testCases) {
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final CoordinatorLayout.LayoutParams lp =
+ (CoordinatorLayout.LayoutParams) view.getLayoutParams();
+ lp.gravity = testCase[0];
+ view.setLayoutParams(lp);
+ }
+ });
+ instrumentation.waitForIdleSync();
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertThat("Gravity: " + testCase[0], view.getLeft(), is(testCase[1]));
+ assertThat("Gravity: " + testCase[0], view.getTop(), is(testCase[2]));
+ }
+ });
+ }
+ }
+
+ @Test
public void testInsetDependency() {
final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;