Android Tips #34 Android 2.1 から GridLayout を使う

catch

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

GridLayout が Android 2.1 から使える!

GridLayout は Android 3.0 (APIレベル11) で新たに導入されたレイアウトです。View を Grid 式にレイアウトすることができる、なんで今までなかったの!ってぐらい便利なレイアウトです。このレイアウトですが Support Package v7 を使うと Android 2.1 (APIレベル7) から使うことができます!
Support Package v7 はよく使われる Support Package (プロジェクト作成時につくられるライブラリ) とは導入方法が異なるので、その手順から解説したいと思います。

gridlayout06

Support Package v7 の導入方法

1. Support Package をインストールする

まずは Support Package をインストールします。SDK Manager を起動し Support Package にチェックを入れてインストールします。

gridlayout01

2. ライブラリプロジェクトをインポートする

次に GridLayout のライブラリプロジェクトをワークスペースにインポートします。メニューより「File > Import...」を選び「Existing Android Code Into Workspace」を選びます。Root Directory は以下を指定します。

${SDK_ROOT}/extras/android/support/v7/gridlayout

SDK フォルダを汚したくない場合は「Copy projects into workspace」にチェックを入れておきます。

gridlayout02

追加すると下図のようになります。

gridlayout03

3. ライブラリをプロジェクトに追加する

最後に上記ライブラリをプロジェクトに追加して完了です。まずプロジェクトを右クリックし、コンテキストメニューから「Properties」を選択し、プロジェクトプロパティを開きます。

gridlayout04

Android 設定の Library で Add ボタンをクリックして、先ほど追加した ライブラリプロジェクトを選択して完了です。

gridlayout05

GridLayout の使いかた

レイアウトの定義

まずレイアウトの定義ですが、以下のように GridLayout の定義は <GridLayout> ではなく <android.support.v7.widget.GridLayout> と記述します。また名前空間は http://schemas.android.com/apk/res-auto を指定します。このように指定することでライブラリが複数ある場合にひとつの名前空間に統一することができます。最低限必要なのが行数と列数の指定です。 app:columnCount が行数、 app:rowCount が列数です。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="4"
    app:rowCount="3">
</android.support.v7.widget.GridLayout>

まずはシンプルにレイアウトしてみる

ということでまずはシンプルなレイアウト例です。3行、3列のグリッドをレイアウトしてみます。子の View には app:layout_column でどの行に配置するか、 app:layout_row でどの列に配置するか指定しています。行と列は 0 から始まる点に注意してください。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="3"
    app:rowCount="3">
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="1"
        app:layout_column="0"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="2"
        app:layout_column="1"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="3"
        app:layout_column="2"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="4"
        app:layout_column="0"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="5"
        app:layout_column="1"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="6"
        app:layout_column="2"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="7"
        app:layout_column="0"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="8"
        app:layout_column="1"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="9"
        app:layout_column="2"
        app:layout_row="2"
        />
    
</android.support.v7.widget.GridLayout>

gridlayout06

こんな感じにレイアウトすることもできます。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="3"
    app:rowCount="3">
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="1"
        app:layout_column="0"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="2"
        app:layout_column="2"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="3"
        app:layout_column="1"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="4"
        app:layout_column="0"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="5"
        app:layout_column="2"
        app:layout_row="2"
        />
    
</android.support.v7.widget.GridLayout>

gridlayout07

行または列をまたぐ

行をまたぐには app:layout_columnSpan を使います。指定した数値ぶんの行をまたいでくれます。列の場合は app:layout_rowSpan です。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="3"
    app:rowCount="3">
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="1"
        app:layout_column="0"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="240dp"
        android:layout_height="80dp"
        android:text="2"
        app:layout_column="1"
        app:layout_columnSpan="2"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="160dp"
        android:text="3"
        app:layout_column="0"
        app:layout_row="1"
        app:layout_rowSpan="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="4"
        app:layout_column="1"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="5"
        app:layout_column="2"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="6"
        app:layout_column="1"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="7"
        app:layout_column="2"
        app:layout_row="2"
        />
    
</android.support.v7.widget.GridLayout>

gridlayout08

View の位置を指定する

子の View を配置する位置を指定するには app:layout_gravity を使います。指定された行・列の中で gravity をとります。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="3"
    app:rowCount="3" >
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="1"
        app:layout_column="0"
        app:layout_columnSpan="2"
        app:layout_row="0"
        app:layout_rowSpan="2"
        app:layout_gravity="center"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="2"
        app:layout_column="2"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="3"
        app:layout_column="2"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="4"
        app:layout_column="0"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="5"
        app:layout_column="1"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="6"
        app:layout_column="2"
        app:layout_row="2"
        />
    
</android.support.v7.widget.GridLayout>

gridlayout09

Space で空間をあける

行の高さは保持しておきたいけど View は配置したくないといった、特定の行または列に空間をあけておきたい場合があります。そのときは Space の Support Package v7 版である android.support.v7.widget.Space を使います。以下では2行目に Space を使って空間をあけています。

<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:columnCount="3"
    app:rowCount="3">
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="1"
        app:layout_column="0"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="2"
        app:layout_column="1"
        app:layout_row="0"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="3"
        app:layout_column="2"
        app:layout_row="0"
        />
    
    <android.support.v7.widget.Space 
        android:layout_width="360dp"
        android:layout_height="40dp"
        app:layout_column="0"
        app:layout_columnSpan="3"
        app:layout_row="1"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="4"
        app:layout_column="0"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="5"
        app:layout_column="1"
        app:layout_row="2"
        />
    
    <Button 
        android:layout_width="120dp"
        android:layout_height="80dp"
        android:text="6"
        app:layout_column="2"
        app:layout_row="2"
        />
    
</android.support.v7.widget.GridLayout>

gridlayout11

Java から動的につくる

最後に Java から動的につくってみたいと思います。LayoutParams を使ってレイアウトを設定し addView() するだけなので特別に難しいことはありません。子 View に対する column と raw の指定には Spec を使って指定します。Spec インスタンスは GridLayout#spec() で取得できます(static メソッド)。任意の Spec を取得し、 LayoutParams.columnSpec と LayoutParams.rowSpec に代入します。いずれもコードヒントで出てくる標準 API のほうを import しないよう注意して実装しましょう。

gridlayout10

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    GridLayout layout = new GridLayout(this);
    layout.setColumnCount(3);
    layout.setRowCount(3);
    setContentView(layout);
    
    Button button1 = new Button(this);
    GridLayout.LayoutParams params1 = new GridLayout.LayoutParams();
    params1.width = 180;
    params1.height = 120;
    params1.columnSpec = GridLayout.spec(0);
    params1.rowSpec = GridLayout.spec(0);
    button1.setLayoutParams(params1);
    button1.setText("1");
    layout.addView(button1);
    
    Button button2 = new Button(this);
    GridLayout.LayoutParams params2 = new GridLayout.LayoutParams();
    params2.width = 180;
    params2.height = 120;
    params2.columnSpec = GridLayout.spec(1);
    params2.rowSpec = GridLayout.spec(0);
    button2.setLayoutParams(params2);
    button2.setText("2");
    layout.addView(button2);
    
    Button button3 = new Button(this);
    GridLayout.LayoutParams params3 = new GridLayout.LayoutParams();
    params3.width = 180;
    params3.height = 120;
    params3.columnSpec = GridLayout.spec(2);
    params3.rowSpec = GridLayout.spec(0);
    button3.setLayoutParams(params3);
    button3.setText("3");
    layout.addView(button3);
    
    Space space = new Space(this);
    GridLayout.LayoutParams spaceParams = new GridLayout.LayoutParams();
    spaceParams.width = 0;
    spaceParams.height = 60;
    spaceParams.columnSpec = GridLayout.spec(0, 3);
    spaceParams.rowSpec = GridLayout.spec(1);
    space.setLayoutParams(spaceParams);
    layout.addView(space);
    
    Button button4 = new Button(this);
    GridLayout.LayoutParams params4 = new GridLayout.LayoutParams();
    params4.width = 180;
    params4.height = 120;
    params4.columnSpec = GridLayout.spec(0);
    params4.rowSpec = GridLayout.spec(2);
    button4.setLayoutParams(params4);
    button4.setText("4");
    layout.addView(button4);
    
    Button button5 = new Button(this);
    GridLayout.LayoutParams params5 = new GridLayout.LayoutParams();
    params5.width = 180;
    params5.height = 120;
    params5.columnSpec = GridLayout.spec(1);
    params5.rowSpec = GridLayout.spec(2);
    button5.setLayoutParams(params5);
    button5.setText("5");
    layout.addView(button5);
    
    Button button6 = new Button(this);
    GridLayout.LayoutParams params6 = new GridLayout.LayoutParams();
    params6.width = 180;
    params6.height = 120;
    params6.columnSpec = GridLayout.spec(2);
    params6.rowSpec = GridLayout.spec(2);
    button6.setLayoutParams(params6);
    button6.setText("6");
    layout.addView(button6);
    
}

「Space で空間をあける」で書いたサンプルと同じレイアウトになるはずです。

gridlayout11

まとめ

はじめにも書きましたが、GridLayout は「なんで今までなかったの!?」ってぐらい便利なレイアウトです。いままで LinearLayout で頑張って作っていたかたも多いと思いますが GridLayout を使うことでラクラク実装ができるので、かなりオススメです!今回のサンプルをぜひ参考にして使っていただければと思います。

参考