GridLayout align children within column

Chris Horner picture Chris Horner · Aug 20, 2014 · Viewed 19.6k times · Source

I have a GridLayout that consists of 6 children. It has a column count of 2. The left column's children have a layout_gravity of start|end|fill_horizontal and layout_width of 0dp, which causes them to fill all available space.

This is great, and gives me the output shown below. enter image description here

Views 4, 5, and 6 are only as big as they need to be. Very cool. I would now like to align views 4, 5, and 6 to the right hand side of the container, but this has proved challenging. Because of the way GridLayout determines column flexibility, giving the right column's views a layout_gravity of right ruins the layout. Views in the first column no longer fill the remaining width in the layout. (From my understanding, this is because now both columns have children defining a horizontal gravity, so GridLayout can no longer mark one column as flexible).

Is there a way to achieve this? I'm really not keen on nesting LinearLayouts. Below is my desired result.

enter image description here

For reference, the current view hierarchy XML looks something like...

<GridLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="2">

    <View
        android:id="@+id/view1"
        android:layout_gravity="start|end|fill_horizontal" />

    <View
        android:id="@+id/view4" />

    <View
        android:id="@+id/view2"
        android:layout_gravity="start|end|fill_horizontal" />

    <View
        android:id="@+id/view5" />

    <View
        android:id="@+id/view3"
        android:layout_gravity="start|end|fill_horizontal" />

    <View
        android:id="@+id/view6" />

</GridLayout>

Answer

Infinite Recursion picture Infinite Recursion · Sep 2, 2014

From the Documentation of GridLayout:

Excess Space Distribution

Multiple components in the same row or column group are considered to act in parallel. Such a group is flexible only if all of the components within it are flexible. Row and column groups that sit either side of a common boundary are instead considered to act in series. The composite group made of these two elements is flexible if one of its elements is flexible.

To make a column stretch, make sure all of the components inside it define a gravity. To prevent a column from stretching, ensure that one of the components in the column does not define a gravity.

When the principle of flexibility does not provide complete disambiguation, GridLayout's algorithms favour rows and columns that are closer to its right and bottom edges.

(emphasis mine)

So, to design the following output: enter image description here

Explanation:

enter image description here

Note:

  • Don't align the gravity of the largest width component of the right column with any axis (such as top, bottom, left, right). When a view is aligned w.r.t to axis, it will not stretch because the composite group will become non-flexible. This will make the other elements in the composite group shrink (even if fill_horizontal is specified, it will be ineffective in a non-flexible composite group). The width of the widest component will be the width of the right side column in the grid.

  • If you want the text to wrap when the length of the content increases, specify width of the view as 0dp (android:layout_width="0dp"), so that the grid layout will dynamically calculate the width:

enter image description here

XML for the grid layout:

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:alignmentMode="alignBounds"
    android:background="#ffffffff"
    android:columnCount="6"
    android:columnOrderPreserved="false"
    android:orientation="horizontal"
    android:padding="5dp"
    android:useDefaultMargins="true" >

    <Button
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_columnSpan="4"
        android:layout_gravity="left|fill"
        android:background="#ff00BFFF"
        android:text="View 1" />

    <Button
        android:id="@+id/view4"
        android:layout_columnSpan="2"
        android:layout_gravity="right|clip_horizontal"
        android:background="#ffff0000"
        android:padding="5dp"
        android:text="hi"
        android:textColor="#ffffffff" />

    <Button
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_columnSpan="4"
        android:layout_gravity="left|fill"
        android:background="#ff00ff00"
        android:text="View 2 has a very very very long text" />

    <Button
        android:id="@+id/view5"
        android:layout_columnSpan="2"
        android:layout_gravity="clip_horizontal"
        android:background="#ffDDA0DD"
        android:padding="5dp"
        android:text="hello something"
        android:textColor="#ffffffff" />

    <Button
        android:id="@+id/view3"
        android:layout_width="0dp"
        android:layout_columnSpan="4"
        android:layout_gravity="left|fill"
        android:background="#ffffD700"
        android:text="View 3 has a very very very long text" />

    <Button
        android:id="@+id/view6"
        android:layout_columnSpan="2"
        android:layout_gravity="clip_horizontal|right"
        android:background="#ff4169E1"
        android:padding="5dp"
        android:text="hello world"
        android:textColor="#ffffffff" />

</GridLayout>