4

Consider the following trivial layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="top" >

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

    </LinearLayout>

</LinearLayout>

The outer LinearLayout specifies that it has

android:gravity="bottom"

which means that it wants its children to "fall to the bottom".

The inner LinearLayout specifies that

android:layout_gravity="top"

which means that it wants itself to be laid out at the top of its enclosing layout. (To specify android:layout_gravity one must apparently edit the XML file directly. There does not seem to be a way to reach that attribute from Eclipse. Anyhow...)

How does Android resolve such a conflict? The example above suggests that the gravity attribute overrides the layout_gravity attribute. Is that how the conflict is resolved in general?

Calaf
  • 10,113
  • 15
  • 57
  • 120

1 Answers1

1

From taking a look at the layoutVertical() method in LinearLayout, the gravity of the LinearLayout itself is what determines how the children are positioned.

The layout_gravity of each child is used only for laying out "in the other direction" (i.e. left-right).

First:

    final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
    final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;

    switch (majorGravity) {
       case Gravity.BOTTOM:
           childTop = ... 
           break;

       // ... same for CENTER_VERTICAL and TOP
    }

Then, for each child:

    for (int i = 0; i < count; i++) {
        final View child = getVirtualChildAt(i);

        final LinearLayout.LayoutParams lp =
                (LinearLayout.LayoutParams) child.getLayoutParams();

        int gravity = lp.gravity;
        if (gravity < 0) {
            gravity = minorGravity;
        }

        final int layoutDirection = getLayoutDirection();
        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
            case Gravity.CENTER_HORIZONTAL:
                childLeft = ...
                break;

            // ... same for RIGHT and LEFT

And equivalently for layoutHorizontal().

Also, just a comment but android:layout_gravity can be accessed from Java code. It's the gravity field in the LinearLayout.LayoutParams class (which is set as the LayoutParams of the child view).

matiash
  • 54,791
  • 16
  • 125
  • 154