GridLayout align children within column
Asked Answered
A

2

16

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>
Annis answered 20/8, 2014 at 2:18 Comment(4)
Just for clarification: do you want to just fill the space up for the right column or should the right column have the same width as the left column? Do you want to also right align the text in the second column?Sidonius
I'd like the views in the right column to keep their current width. I want the bounds of the views to hug the right hand side, rather than the left. The text will indeed be right aligned, but the internal gravity of TextViews doesn't seem relevant to the problem.Annis
how abt table layout i would like to try this ..can't you use table layoutBridge
It's certainly possible to achieve the look of what I want with a TableLayout, but that's not question. I'm interested in whether or not what I want is possible with a GridLayout. A TableLayout will use multiple layout() passes to get the job done. A GridLayout would be much more efficient.Annis
T
18

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>
Topdrawer answered 2/9, 2014 at 12:25 Comment(6)
If you use android:text="View 3 and a little bit longer to break the length" for the view3 then it pushes the right column out of the screen. As Chris mentions if any of the view 1,2,3 is long it does not break into a new line. It pushes the content out.Sidonius
Thanks very much for your help! Seems like it's impossible to do this with only two columns, which is fine. I definitely learnt a lot about GridLayout from this little exercise!Annis
@Chris: Hope you read this - android-developers.blogspot.com/2011/11/…, I find it very useful.Topdrawer
@InfiniteRecursion I have indeed read that many times, but I find it still doesn't give a clear picture of GridLayout's capabilities. I started this goose chase because GridLayout.Alignment seemed to hint at certain possibilities developer.android.com/reference/android/widget/…Annis
This assumes you know which view will have the longest text. Even assuming static data, what's longest in English may not be longest in another language.Pacificism
With views in the 2nd column aligned to the right, how to make columns equal in width? stackoverflow.com/questions/74300204Aborigine
S
2

Let me modify my answer and use a different approach. This is the layout file:

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2" >


<TextView
    android:id="@+id/TextView1"
    android:layout_column="0"
    android:layout_columnSpan="1"
    android:layout_row="0"
    android:background="#87CEFA"
    android:text="@string/view1" />

<TextView
    android:id="@+id/TextView4"
    android:gravity="right"
    android:layout_column="1"
    android:layout_columnSpan="1"
    android:layout_row="0"
    android:layout_gravity="right"
    android:background="#FF3030"
    android:text="@string/view4" />

<TextView
    android:id="@+id/TextView2"
    android:layout_column="0"
    android:layout_columnSpan="1"
    android:layout_row="1"
    android:width="0dp"
    android:layout_gravity="fill_horizontal"
    android:background="#90EE90"
    android:text="@string/view2" />

<TextView
    android:id="@+id/TextView5"
    android:gravity="right"
    android:layout_column="1"
    android:layout_columnSpan="1"
    android:layout_row="1"
    android:background="#EE82EE"
    android:paddingLeft="36dp"
    android:layout_gravity="right"
    android:text="@string/view5" />

<TextView
    android:id="@+id/TextView3"
    android:layout_column="0"
    android:layout_columnSpan="1"
    android:layout_row="2"
    android:width="0dp"
    android:layout_gravity="fill_horizontal"
    android:background="#EEEE00"
    android:text="@string/view3" />

<TextView
    android:id="@+id/TextView6"
    android:gravity="right"
    android:layout_column="1"
    android:layout_columnSpan="1"
    android:layout_row="2"
    android:background="#EE7621"
    android:layout_gravity="right"
    android:text="@string/view6" />

</GridLayout>

And here is the result:

enter image description here

The width of both column is driven by the content. For View 5 I added padding on the left side i.e. padding could be used to extend the width (and height) of the cells. Would this work?

Sidonius answered 21/8, 2014 at 15:35 Comment(4)
That's a lot of effort for an answer, nice work! Unfortunately, it's not quite what I'm after. (I've just updated the question to clarify what I'm after. Apologies for any vagaries). I also wouldn't be keen on manually adjusting with width of children myself. I'm fairly certain GridLayout can do what I'm asking, I'm justing missing some key detail.Annis
Closer, but that approach still has a problem. If the length of the text in Views 1, 2, or 3 is particularly long, it will not go onto a new line. Unfortunately, the text will continue right and extend outside the View's bounds. The only way I've found to prevent this is to set the width to 0dp, and layout_gravity to fill_horizontal. That in turn means that layout_gravity cannot be right on the views in the second column :(Annis
Yes, that is the challenge. I referred to it as "driven by content". The only way I have found so far was my first response. I am going to watch this entry to see if someone has a better solution.Sidonius
any chance to achieve this result programmatically?Nf

© 2022 - 2024 — McMap. All rights reserved.