Heterogeneous GridLayout

C.d. picture C.d. · May 30, 2012 · Viewed 39.6k times · Source

I am trying to implement the layout below:

Target Layout

I guess GridLayout is suitable for my needs but after 2 hours of struggle I couldn't create even a similar layout.. The layout is resizing itself wrongly, it exceeds the screen of the phone and it also does not span the specified rows and columns.

Here I selected a button so you can see how it exceeds the boundaries:

Fail

and here is the associated xml code: https://gist.github.com/2834492

I have reached a similar layout with nested linearlayouts but it's not possible to properly resize it for different screen sizes.


UPDATE - approximate LinearLayout implementation:

The XML code: https://gist.github.com/cdoger/2835887 However, the problem is it does not resize itself properly here some screenshots with different screen configurations:

enter image description here

enter image description here

enter image description here


TLDR: Can someone show me a heterogeneous layout implementation with GridLayout like in the first picture?

Answer

Fuzzical Logic picture Fuzzical Logic · Jun 7, 2012

The issue you are facing is due to inappropriate use of the GridLayout. The GridLayout is made to show its children in a grid and you are trying to override that without extending the GridLayout. While what you want may be accomplished in code (utilizing numcolumns and columnsize), it will not be useful for multiple screen sizes without a heck of a lot of code.

The only adequate solution that won't require a ton of hacking is judicious use of both LinearLayout and RelativeLayout. LinearLayout should not be used exclusively as it is made to drop items in a line (horizontally or vertically only). This becomes especially apparent when you try and do the bottom four buttons. While the buttons above may be done with LinearLayout with very little effort, RelativeLayout is what you need for the bottom four buttons.

Note: RelativeLayout can be a little bit tricksy for those with little experience using them. Some pitfalls include: children overlapping, children moving off the screen, height and width rendering improperly applied. If you would like an example, let me know and I will edit my answer.

Final Note: I'm all for utilizing the current framework objects in unique ways, and genuinely prefer to provide the requested solution. The solution, however, is not viable given the constraints of the question.

(Revision) Solution 1

After some careful thought last night, this may be accomplished with a pure LinearLayout. While I do not like this solution, it should be multi-screen friendly and requires no tooling around from me. Caution should be used with too many LinearLayouts, as according to Google's developers, it can result in slow loading UIs due to the layout_weight property. A second solution utilizing RelativeLayout will be provided when I return home. Now Tested This provides the desired layout parameters on all screen-sizes and orientations.

<?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:orientation="vertical" > 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">
        <LinearLayout 
            android:layout_width="match_parent" 
            android:layout_height="0dp" 
            android:layout_weight="1" 
            android:orientation="horizontal"> 
            <Button 
                android:id="@+id/Button01" 
                android:layout_width="0" 
                android:layout_height="match_parent" 
                android:layout_weight="1" 
                android:text="Button" />     
            <Button 
                android:id="@+id/Button02" 
                android:layout_width="0" 
                android:layout_height="match_parent" 
                android:layout_weight="1" 
                android:text="Button" />     
        </LinearLayout> 
        <Button 
            android:id="@+id/button3" 
            android:layout_width="match_parent" 
            android:layout_height="0dp"
            android:layout_weight="1" 
            android:text="Button" />   
        <LinearLayout 
            android:layout_width="match_parent" 
            android:layout_height="0dp" 
            android:layout_weight="1.00"
            android:orientation="horizontal">  
            <Button 
                android:id="@+id/button1" 
                android:layout_width="0dp" 
                android:layout_height="match_parent" 
                android:layout_weight="1" 
                android:text="Button" />   
            <Button 
                android:id="@+id/button2" 
                android:layout_width="0dp" 
                android:layout_height="match_parent" 
                android:layout_weight="1" 
                android:text="Button" />     
        </LinearLayout>
    </LinearLayout>    
    <LinearLayout 
        android:layout_width="match_parent" 
        android:layout_height="0dp" 
        android:layout_weight="1" 
        android:orientation="horizontal">     
        <LinearLayout 
            android:layout_width="0dp" 
            android:layout_height="match_parent" 
            android:layout_weight="1" 
            android:orientation="vertical" >    
            <Button 
                android:id="@+id/button4" 
                android:layout_width="match_parent" 
                android:layout_height="0dp"
                android:layout_weight="1" 
                android:text="Button" />     
            <Button 
                android:id="@+id/button5" 
                android:layout_width="match_parent" 
                android:layout_height="0dp" 
                android:layout_weight="2" 
                android:text="Button" />     
        </LinearLayout>     
        <LinearLayout 
            android:layout_width="0dp" 
            android:layout_height="match_parent" 
            android:layout_weight="1" 
            android:orientation="vertical" > 
            <Button 
                android:id="@+id/button6" 
                android:layout_width="match_parent" 
                android:layout_height="0dp" 
                android:layout_weight="2" 
                android:text="Button" /> 
            <Button 
                android:id="@+id/button7" 
                android:layout_width="match_parent" 
                android:layout_height="0dp" 
                android:layout_weight="1" 
                android:text="Button" /> 
        </LinearLayout> 
    </LinearLayout> 
</LinearLayout> 

Solution 1 Explanation

The key to LinearLayouts is to define your imperatives as separate Layouts and nest the others in them. As you apply constraints to more dimensions, more LinearLayouts must be added to encapsulate the others. For yours, it was crucial to have two more parents in order to maintain the proportion. A great indicator of when you should add another level is when you have to utilize layout_weight using anything other than an integer value. It simply becomes to hard to calculate properly. From there it was relatively simple to break it into columns.

Solution 2 (Failed)

While I was able to achieve desirable results utilizing RelativeLayout and "struts", I could only do so with layouts that were multiples of 2 buttons in height. Such a trick would be awesome as the levels of layout are greatly reduced, so I will work on a pure XML solution and post the answer here if and when I achieve it. In the meantime, the LinearLayout above should suit your needs perfectly.