セクションヘッダー付きの GridView で、かつ「もっと読む」とか「PullToRefresh」もしたい

ListView を用いて、ListView の中に GridView をねじ込んで実装する。

```
+--------------------+
|   Header content   |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
|   Header content   |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
| Cell | Cell | Cell |
+------+------+------+
...
```

## データ構造

一行分のデータを表すデータ構造は、

- セクションヘッダーとして取り扱う為のデータ
- GridView に表示するリストのデータ

このデータ構造を保持するコレクションを作って、ListView のアダプターに渡していくスタイル。

```java
public class SectionData {
    private String mSectionName;
    private List<String> mImages;
}
```

## レイアウト

リストの一行ごとに、GridView をねじ込んでいくスタイル。こうすれば、一行ごとのレイアウトに、GridView のセクションヘッダーの役割を果たすレイアウトを含めることが出来る。

このとき、スクロールのハンドリングが ListView と GridView で二重化してしまうので、GridView のスクロールをしないよう、高さを中身の数に合わせて固定化する（[参考リンク](http://stackoverflow.com/questions/3862281/add-a-gridview-to-a-listview-in-android)）。

```java
// StackOverFlow の回答の実装
public class NonScrollableGridView extends GridView {
    public NonScrollableGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Do not use the highest two bits of Integer.MAX_VALUE because they are
        // reserved for the MeasureSpec mode
        int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightSpec);
        getLayoutParams().height = getMeasuredHeight();
    }
}
```

## アダプター

ListView 用のアダプターと、GridView 用のアダプターを用意する。

ListView 用のアダプターの `ListAdapter#getView(int, View, ViewGroup)`では、GridView の初期化と GridView 用のアダプターの初期化および設定をする。

```java
public class SectionListAdapter extends ArrayAdapter<SectionData> {
    public SectionListAdapter(Context context, List<SectionData> objects) {
        super(context, R.layout.list_item_layout, R.id.label_section_title, objects);
    }

    @Nullable
    @Override
    public View getView(int position, View convertView, ViewGroup group) {
        View row = super.getView(position, convertView, group);

        SectionData data = getItem(position);

        TextView sectionName = (TextView) row.findViewById(R.id.label_section_name);
        sectionName.setText(data.getSectionName());

        GridView grid = (GridView) row.findViewById(R.id.grid);
        SectionGridAdapter adapter = new SectionGridAdapter(getContext(), data.getImageUrls());
        grid.setAdapter(adapter);

        return row;
    }
}
```

GridView 用のアダプターは、いつもどおりセルのレイアウトを生成するコードを書く。

```java
public class SectionGridAdapter extends ArrayAdapter<String> {
    public SectionGridAdapter(Context context, List<String> objects) {
        super(context, R.layout.grid_item, R.id.label_grid, objects);
    }

    @Nullable
    @Override
    public View getView(int position, View convertView, ViewGroup group) {
        View cell = super.getView(position, convertView, group);

        ImageView image = (ImageView) cell.findViewById(R.id.image_cell);
        // Picasso 使うなら
        Picasso.with(getContext()).load(getItem(position)).into(image);

        return cell;
    }
}
```

## もっと読むとか PullToRefresh とか

ListView なので、もっと読むは FooterView が使える。

PullToRefresh も、[このライブラリ](https://github.com/chrisbanes/Android-PullToRefresh)であれば、ListView を PullToRefreshListView に置き換えて使うことができる。

簡単！