Wear用ViewのGridViewPagerを使う

`GridViewPager`はAndroidWear用の新しいビューです。`ViewPager`はスワイプで左右のページに移動できましたが、`GridViewPager`は名前の通り`ViewPager`のグリッド版で、上下左右のページに移動できます。

# 準備

Wearモジュールのbuild.gradleに次の依存関係を設定します。AndroidStudioでWearモジュールを追加、あるいはWearを含むプロジェクトの新規作成をすれば自動で下記の設定がされているはずです。

```groovy
compile 'com.google.android.support:wearable:+'
```

# GridViewPagerを使う

## レイアウト

```activity_main.xml
<android.support.wearable.view.GridViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridViewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
```

## アダプタの設定

`ViewPager`と同様にアダプタを設定する必要があります。いろいろ細かいところを省いてシンプルにするとこんな感じ。

```MainActivity.java
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final GridViewPager gridViewPager = (GridViewPager) findViewById(R.id.gridViewPager);
        gridViewPager.setAdapter(new MyAdapter(getFragmentManager()));
    }
}
```

## アダプタの作成

アダプタには`GridPagerAdapter`を使用しますが、今回はそのサブクラスの`FragmentGridPagerAdapter`を使ってみます。

### FragmentGridPagerAdapterのコンストラクタと抽象メソッド

`FragmentGridPagerAdapter`のサブクラスを作って、最低限必要なコンストラクタとメソッドをIDEに自動生成させるとこんな感じになります。

```java
public static class MyAdapter extends FragmentGridPagerAdapter {

    public MyAdapter(final FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getFragment(final int row, final int column) {
        return null;
    }

    @Override
    public int getRowCount() {
        return 0;
    }

    @Override
    public int getColumnCount(final int row) {
        return 0;
    }
}
```

`FragmentGridPagerAdapter`は`FragmentManager`を取るコンストラクタを定義しているので、サブクラスのコンストラクタで適切に呼び出してやる必要があります。
`getFragment`メソッドは、与えられた行と列(`row`と`column`)に対応するフラグメントを返します。
`getRowCount`メソッドは行数を、`getColumnCount`メソッドは与えられた行に対応する列数を返します。

例えば3行4列のページ構成にしたい場合は次のように実装します。

```java
@Override
public int getRowCount() {
    return 3;
}

@Override
public int getColumnCount(final int row) {
    return 4;
}
```

行数列数が可変の場合は、例えばこんな感じ。

```java
@Override
public int getRowCount() {
    return categories.size();
}

@Override
public int getColumnCount(final int row) {
    final List<Page> pages = categories.get(row).getPages();
    return pages.size();
}
```

### 背景の設定

ページ毎の背景を設定するには`getBackground`メソッドをオーバライドする必要があります。

```java
@Override
public ImageReference getBackground(final int row, final int column) {
    return ImageReference.forDrawable(R.drawable.background);
}
```

`ImageReference`は`forBitmap`と`forDrawable`、`forImageUri`の3つの`static`メソッドを持っているので、これを使って簡単に生成することができます。

# CardFragmentを使う

`FragmentGridPagerAdapter`の`getFragment`メソッドで、フラグメントを返す必要があります。ここで普通の`Fragment`を使うことももちろんできますが、せっかくなのでWear用に新しく登場した`CardFragment`を使ってみましょう。タイトルと説明(あとアイコン)のみ表示すればいい、レイアウトはこだわらないというのであれば`CardFragment`は一瞬で作れます。

![device-2014-07-10-210002.png](https://qiita-image-store.s3.amazonaws.com/0/15731/03bf1f56-9700-98f6-142c-118014924cfc.png)

このような`CardFragment`を作るにはこう記述するだけです。

```java
CardFragment.create("title", "description", R.drawable.ic_launcher);
```

最後の引数でアイコンを指定していますが、これはオプションです。

## カスタムレイアウト

自分で定義したレイアウトを使いたい場合は`CardFragment`を継承し、`onCreateContentView`メソッドを適切にオーバライドします。`Fragment#onCreateView`と引数は同じで、使い勝手も同じです。

## CardFragmentの設定

### 展開の禁止

先の例の"description"を表示する部分はデフォルトで、表示する文字数に応じて縦に展開されます。これを禁止するには、つまり表示する文字を途中で切ってスクロールをさせないためには次のように設定します。

```java
cardFragment.setExpansionEnabled(false);
```

### 展開方向の設定

表示文字数が多い場合の、カードが展開される方向を設定します。

```java
cardFragment.setExpansionDirection(CardFragment.EXPAND_UP);
```

`EXPAND_DOWN`の場合 (デフォルト)

![device-2014-07-10-211235.png](https://qiita-image-store.s3.amazonaws.com/0/15731/a60c655e-cdd2-8470-4158-373a247cd8ab.png)

`EXPAND_UP`の場合

![device-2014-07-10-211207.png](https://qiita-image-store.s3.amazonaws.com/0/15731/2450d419-b245-e0fd-9bbc-8a9fa33eb445.png)

### 高さの最大値の設定

カードの高さの最大値を親の高さの何倍か、というような設定ができます。

```java
// 最大でも親の1.5倍の高さ
cardFragment.setExpansionFactor(1.5f);
```

### カードのグラビティ設定

カードのグラビティを設定します。

```java
cardFragment.setCardGravity(Gravity.TOP);
```
デフォルトは`Gravity.DOWN`です。設定できる値は`Gravity.TOP`か`Gravity.DOWN`のみです。