Flutterのチュートリアルを学んでみた(11)

# GridViewで写真ギャラリーを作ろう！ 📸

## GridViewって何？ 🤔

インスタグラムのような写真ギャラリーを作りたいことありませんか？
そんなときに使うのが`GridView`です！
格子状（こうしじょう）に並べて、スクロールできる画面が作れます。

## GridViewを作る3つの方法 🎨

### 1. 数で指定（GridView.count）
写真を何枚ずつ横に並べるか指定する方法：

```dart
GridView.count(
  crossAxisCount: 2,  // 横に2枚ずつ
  children: [
    Image.asset('photo1.jpg'),
    Image.asset('photo2.jpg'),
    Image.asset('photo3.jpg'),
    Image.asset('photo4.jpg'),
  ],
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/12d29d23-43fa-d170-6906-4055d9fe02ac.png)


使い道：
- 写真ギャラリー
- アプリのメニュー
- 商品一覧

### 2. サイズで指定（GridView.extent）
それぞれの写真の最大幅を指定する方法：

```dart
GridView.extent(
  maxCrossAxisExtent: 150,  // 最大幅150px
  padding: EdgeInsets.all(4),
  mainAxisSpacing: 4,      // 縦の間隔
  crossAxisSpacing: 4,     // 横の間隔
  children: [
    Image.asset('photo1.jpg'),
    Image.asset('photo2.jpg'),
    Image.asset('photo3.jpg'),
  ],
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/47bf0371-6e27-f438-ed5a-a3b8c66a6265.png)


### 3. ビルダー方式（GridView.builder）
たくさんの写真や無限スクロールに最適！

```dart
GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,  // 横に2枚ずつ
  ),
  itemBuilder: (context, index) {
    return Image.asset('photo$index.jpg');
  },
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/d4ef0bdf-6409-ee61-9171-9073dbfc373c.png)


## 写真の間に隙間を作る 📏

### 縦の隙間を作る
```dart
GridView.count(
  crossAxisCount: 2,
  mainAxisSpacing: 10,  // 10pxの縦の隙間
  children: [/*...*/],
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/5c8a3594-ea1c-80ed-283e-6a9fde566b4d.png)


### 横の隙間を作る
```dart
GridView.count(
  crossAxisCount: 2,
  crossAxisSpacing: 10,  // 10pxの横の隙間
  children: [/*...*/],
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/34e27042-580a-0372-9bac-c8f2ff3a8bac.png)


## 写真の形を変える 🖼

写真の縦横比を変更できます：

```dart
GridView.count(
  crossAxisCount: 2,
  childAspectRatio: 0.7,  // 縦長に
  children: [/*...*/],
)
```

- 1.0: 正方形
- 0.7: 縦長
- 1.5: 横長

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929117/db168425-a0db-0d42-8d99-00733190421a.png)


## 横スクロールにする ↔️

```dart
GridView.builder(
  scrollDirection: Axis.horizontal,  // 横スクロール
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,  // 縦に2枚
  ),
  itemBuilder: (context, index) {
    return Image.asset('photo$index.jpg');
  },
)
```

## やってみよう！ 💪

1. シンプルな写真ギャラリー
```dart
GridView.count(
  crossAxisCount: 3,  // 横に3枚
  children: List.generate(9, (index) {
    return Container(
      color: Colors.blue,
      margin: EdgeInsets.all(5),
      child: Center(
        child: Text('写真 $index'),
      ),
    );
  }),
)
```

2. おしゃれな商品一覧
```dart
GridView.extent(
  maxCrossAxisExtent: 200,
  padding: EdgeInsets.all(8),
  mainAxisSpacing: 8,
  crossAxisSpacing: 8,
  children: List.generate(12, (index) {
    return Card(
      child: Column(
        children: [
          Image.asset('product$index.jpg'),
          Text('商品名 $index'),
          Text('¥1,000'),
        ],
      ),
    );
  }),
)
```

## こんなときはどうする？ 🆘

- 写真がはみ出る
  → BoxFit.coverを使う
- スクロールできない
  → 親ウィジェットの制約を確認
- 間隔がおかしい
  → spacingの値を調整

## 応用テクニック 🚀

1. タップできる写真ギャラリー
```dart
GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 3,
  ),
  itemBuilder: (context, index) {
    return GestureDetector(
      onTap: () {
        print('写真 $index がタップされました');
      },
      child: Image.asset('photo$index.jpg', fit: BoxFit.cover),
    );
  },
)
```

2. アニメーション付きの表示
```dart
GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
  ),
  itemBuilder: (context, index) {
    return AnimatedContainer(
      duration: Duration(milliseconds: 500),
      child: Image.asset('photo$index.jpg'),
    );
  },
)
```