GridLayout——android style

In a recent series of articles, we covered he basic layout types supported by Android. Since those articles were written Google have released the Android 4.0 SDK and there is a new addition: GridLayout. In this series of articles we’ll have a look at GridLayoutand explore the way it works to get a feel for how to use it effectively.

The first thing that strikes you if you look at the GridLayout API is that it offers similar functionality to TableLayout although it goes about it in a rather different way. In fact, it is somewhat more like a hybrid of TableLayout and LinearLayout. Let’s start with a simple example which is similar to what we did when we covered TableLayout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xmlversion="1.0"encoding="utf-8"?>
<GridLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="4"
    android:rowCount="4">
 
    <TextView
        android:text="1,1"/>
    <TextView
        android:text="1,2"/>
    <TextView
        android:text="1,3"/>
    <TextView
        android:text="1,4"/>
    <TextView
        android:text="2,1"/>
    <TextView
        android:text="2,2"/>
    <TextView
        android:text="2,3"/>
    <TextView
        android:text="2,4"/>
    <TextView
        android:text="3,1"/>
    <TextView
        android:text="3,2"/>
    <TextView
        android:text="3,3 longer" />
    <TextView
        android:text="3,4"/>
    <TextView
        android:text="4,1"/>
    <TextView
        android:text="4,2"/>
    <TextView
        android:text="4,3"/>
    <TextView
        android:text="4,4"/>
</GridLayout>

The first thing to point out is that we are not specifying android:layout_width orandroid:layout_height attributes for any of the TextView widgets within the GridLayout. This is because GridLayout uses a different layout model to other layouts as we shall see.

if we run this, we’ll see:

Simple Table

Whil this is pretty close to what we got with TableLayout, there is a difference which is highlighted by the longer text in row 3, cell 3: The cells are not automatically stretched to fill the column as they are in TableLayout. Normally we would look atandroid:layout_width in conjunction with android:layout_weight to control to cell sizes, however GridLayout bases it’s layout model upon the android:layout_gravity of the cells. Normally gravity is used to align the content within a control, but GridLayout uses this to determine the size of cells.

This is easy enough to fix, but it demonstrates a key aspect of how GridLayout works, which we see more of later: How GridLayout sizes each cell is dependent on thelayout_gravity of both the cell itself and its siblings in the same row or column. Let’s demonstrate this by adding android:layout_gravity=”fill_horizontal” to each cell in the third column:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xmlversion="1.0"encoding="utf-8"?>
<GridLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="4"
    android:rowCount="4">
    .
    .
    .
    <TextView
        android:layout_gravity="fill_horizontal"
        android:text="1,3"/>
    .
    .
    .
    <TextView
        android:layout_gravity="fill_horizontal"
        android:text="2,3"/>
    .
    .
    .
    <TextView
        android:layout_gravity="fill_horizontal"
        android:text="3,3 longer" />
    .
    .
    .
    <TextView
        android:layout_gravity="fill_horizontal"
        android:text="4,3"/>
</GridLayout>

This gives us the same as the TableLayout example:

Simple Table with cell stretching

It is important to remember that GridLayout does still support android:layout_width andandroid:layout_height, but default to WRAP_CONTENT for both. However, you can get in to all kinds of problems if you start mixing your layout metaphors, so I would strongly advise leaving android:layout_width and android:layout_height set to their defaults, and control cell widths using android:layout_gravity instead.

This shows some of the parallels with TableLayout, but what about LinearLayout? Similarly to LinearLayout GridLayout supports an android:orientation attribute which controls the order in which GridLayout populates the cells. The default orientation is horizontal, which means that it fills the cells in the first row with the first n children, the cells in the second row with the next n children, and so on (where n is the number of columns). If we change this to “vertical” it will fill the first column with the first m children, the second column with the next m children, and so on (where m is the number of rows). So, by simply changing our GridLayout declaration:

1
2
3
4
5
6
7
8
9
10
<GridLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="4"
    android:rowCount="4"
    android:orientation="vertical">
    .
    .
    .
</GridLayout>

we can change the order in which the cells get populated:

Simple Table with orientation reversed

Note that we have lost the cell stretching of the third column because the relevant cells that we modified earlier now constitute the third row rather than the third column. Let’s revert the orientation of the GridLayout before we continue:

1
2
3
4
5
6
7
8
9
10
<GridLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="4"
    android:rowCount="4"
    android:orientation="horizontal">
    .
    .
    .
</GridLayout>

Another feature of GridLayout is the ability precisely position cells using the layout_rowand layout_column attributes of each child (the cell and column values that you must use here are zero-based, so the first column or cell is 0 and not 1). An important thing to remember about this technique is that if you explicitly set the position of a cell,GridLayout it will effectively move the current position and GridView will continue positioning cells from there. For example, it we switch the position of the cell containing the text “1,3″ the the row below:

1
2
3
4
<TextView
    android:layout_gravity="fill_horizontal"
    android:layout_row="1"
    android:text="1,3"/>

We don’t specify an explicit column because we simply want to more the cell down a row. The specific cell is in the position that we have specified, and the subsequent cells are positioned after it:

Absolute cell positioning

Supposing that we wanted to swap two cells using this technique, we must remember that as well as changing the individual cells that we want to swap, we also need to change the cells that immediately follow those cells:

If we want to swap two cells using this technique we can do this providing we set the required position of each cell, and then reset the position of the following child. So to swap the cells containing text “1,3″ and “2,3″ we need to set the cell locations of both of these cells, and reset the position of the cells which follow each of these:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<TextView
    android:layout_gravity="fill_horizontal"
    android:layout_row="1"
    android:text="1,3"/>
<TextView
    android:layout_row="0"
    android:text="1,4"/>
.
.
.
<TextView
    android:layout_gravity="fill_horizontal"
    android:layout_row="0"
    android:layout_column="2"
    android:text="2,3"/>
<TextView
    android:layout_row="1"
    android:text="2,4"/>

Which gives us:

Swapping two cells

This is all well and good, but why did we need to specify android:layout_column values for TextView 2,3? The reason is that as GridLayout positions each cell, it positionsTextView 2,2 as normal, as it comes to position TextView 2,3 it finds that cell is already occupied by TextView 1,3, so it moves to the next cell (2,4). If we only specify the row for TextView 2,3 then it will only change the row and try and position in the wrong column on the right row, so we need to explicitly set the correct column. This seems a little cofusing, I know, but have a play with it in the Graphical Layout view in ADT and it should begin to make sense.

In the next part of this series we’ll look at how we can span multiple columns or rows with a single cell.

There is now a follow-up article to this series which explains how to use the GridLayout implementation in the support library.

The source code for this article can be found here.

© 2011 – 2013, Mark Allison. All rights reserved. This article originally appeared onStyling Android.

Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章