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

PiperOrigin-RevId: 149329258
This commit is contained in:
Yuichi Araki 2017-03-06 20:20:44 +00:00 committed by Travis Collins
parent 45d961bf72
commit 2cf31d94d3
2 changed files with 69 additions and 6 deletions

View File

@ -1189,11 +1189,18 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
}
/**
* 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;
}
/**
@ -2544,9 +2551,10 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
boolean mBehaviorResolved = false;
/**
* 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.
* A {@link Gravity} value describing how this child view should lay out. 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;

View File

@ -46,6 +46,7 @@ import android.support.test.filters.MediumTest;
import android.support.test.filters.SdkSuppress;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.WindowInsetsCompat;
import android.view.Gravity;
@ -125,6 +126,60 @@ public class CoordinatorLayoutTest {
.onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
}
@Test
public void testLayoutChildren() throws Throwable {
final CoordinatorLayout col = activityTestRule.getActivity().mCoordinatorLayout;
final View view = new View(col.getContext());
activityTestRule.runOnUiThread(
new Runnable() {
@Override
public void run() {
col.addView(view, 100, 100);
}
});
getInstrumentation().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) {
activityTestRule.runOnUiThread(
new Runnable() {
@Override
public void run() {
final CoordinatorLayout.LayoutParams lp =
(CoordinatorLayout.LayoutParams) view.getLayoutParams();
lp.gravity = testCase[0];
view.setLayoutParams(lp);
}
});
getInstrumentation().waitForIdleSync();
activityTestRule.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 = activityTestRule.getActivity().mCoordinatorLayout;