FlutterでQiitaのアプリを作ってみる その2

前回準備とqiitaのAPIをアプリから叩いてみた

https://qiita.com/t0yger/items/c1ea368aab91c1572ccc

repository: 

https://github.com/t0yger/qiita-app

今回はAPIの結果をもって表示させてみたい
かといってFlutterのLayoutの組み方なんて分からないのでまずはリストで適当なものを表示させてみるところを目標とする
とりあえずQiita APIから取得した情報から以下を表示する想定
- user icon
- title
- tags
- 記事の見出し

## Widget
とりあえずFlutterのドキュメントを漁っていると[Widget Catalog](https://docs.flutter.dev/development/ui/widgets)のページを発見
あらかじめ結構な種類のWidgetが用意されている
このWidgetを組み合わせてレイアウトを作っていくっぽい
このWidgetの中からListで表示出来そうなものを探してみると、Material Components widgetsの中から[Grid View](https://api.flutter.dev/flutter/widgets/GridView-class.html)を発見
これを使ってリスト表示をやってみよう
...と思ったがGridViewのドキュメントのサンプルを読み進めると[ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html)を使っている箇所を発見
今回は`ListView` のようにしたいと思っていたのでこちらを使ってみる
後々のことを考えるとAPIのレスポンス次第で要素数は可変になるはずなので`ListView.separated`を採用
`_MyHomePageState`が以下になる
```dart
class _MyHomePageState extends State<MyHomePage> {
  final List<String> entries = <String>['A', 'B', 'C'];
  final List<int> colorCodes = <int>[600, 500, 100];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.separated(
        padding: const EdgeInsets.all(8),
        itemCount: entries.length,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            height: 50,
            color: Colors.amber[colorCodes[index]],
            child: Center(child: Text('Entry ${entries[index]}')),
          );
        },
        separatorBuilder: (BuildContext context, int index) => const Divider(),
      ),
      floatingActionButton: const FloatingActionButton(
        onPressed: null,
        tooltip: 'Search',
        child: Icon(Icons.search),
      ),
    );
  }
}
```
右下のボタンはなんか使いそうな気もするので検索用として残しておきます
起動するとこんな感じ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3077916/186292ff-49fd-db92-41dc-b93c2b40b250.png" width="160" height="320" />

サンプルの通り表示出来ました:tada:
このままだと味気がないので`itemBuilder`の中をもう少し作り込みます
wireframeでこんな感じのイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3077916/3603c0b6-7ffe-d03d-45e4-f99275fe453c.png)
ちなみにこのwireframeは[uizard](https://app.uizard.io/)にあるテンプレートから引っ張ってきてます。手書きのwireframeを自動でデザインに起こしてくれたりします。とても便利

とりあえずググりながらレイアウトの枠組みを組んでみる
borderでContainerの表示領域がどこなのか表示しつつやった結果以下が出来た
```dart
body: ListView.separated(
        padding: const EdgeInsets.all(8),
        itemCount: entries.length,
        itemBuilder: (BuildContext context, int index) {
          return Container(
              height: 150,
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                border: Border.all(
                  color: Colors.red,
                  width: 1.0,
                ),
              ),
              child: Container(
                decoration: BoxDecoration(
                  border: Border.all(
                    color: Colors.black,
                    width: 1.0,
                  ),
                ),
                child: Row(
                  children: [
                    Image.network(
                      'https://picsum.photos/200/300',
                      fit: BoxFit.cover,
                    ),
                    Expanded(
                        child: Container(
                      decoration: BoxDecoration(
                        border: Border.all(
                          color: Colors.green,
                          width: 1.0,
                        ),
                      ),
                      child: Column(
                        children: [
                          Container(
                              alignment: Alignment.centerLeft,
                              decoration: BoxDecoration(
                                border: Border.all(
                                  color: Colors.yellow,
                                  width: 1.0,
                                ),
                              ),
                              child: const Text('article title')),
                          Container(
                              alignment: Alignment.centerLeft,
                              decoration: BoxDecoration(
                                border: Border.all(
                                  color: Colors.blue,
                                  width: 1.0,
                                ),
                              ),
                              child: const Text('tags')),
                          Container(
                              alignment: Alignment.centerLeft,
                              decoration: BoxDecoration(
                                border: Border.all(
                                  color: Colors.grey,
                                  width: 1.0,
                                ),
                              ),
                              child: const Text('headline')),
                        ],
                      ),
                    ))
                  ],
                ),
              ));
        },
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3077916/14b3811b-65dc-1026-049c-a513b5885575.png" width="320" height="480" />

使用したWidgetについて

| widget      | 役割 |
|----------|----------------------------|
| Row | 子要素を横並びにしてくれる |
| Column   | 子要素を縦並びにしてくれる |
| Expanded | 親要素の表示領域に広がってくれる            |
|     Image     | 画像を表示してくれる                           |

なんとなくの大枠は出来た気がするのでborderは全て消してレイアウトを整えていきます
1. アイコンは丸枠のイメージがあるので`Image`を丸枠にしてみる
1. `Row`や`Column`の要素間にmarginを設定したい


1番はググると`CircleAvatar`を使えるというstack overflowが出てきたので使ってみよう
2番もググるとこれまた[overflow](https://stackoverflow.com/questions/53141752/set-the-space-between-elements-in-row-flutter)が既にありました
色々方法があるみたいだが、均等に入れたいわけではないので今回は`SizedBox`を使う方法を採用
結果としてこんなコードになりました
```dart
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.separated(
        padding: const EdgeInsets.all(8),
        itemCount: entries.length,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            height: 150,
            padding: const EdgeInsets.all(16),
            child: Row(
              children: [
                const CircleAvatar(
                    radius: 25,
                    backgroundImage:
                        NetworkImage('https://picsum.photos/200/300')),
                const SizedBox(width: 24),
                Expanded(
                  child: Column(
                    children: [
                      Container(
                          alignment: Alignment.centerLeft,
                          child: const Text(
                            'article title',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 24),
                          )),
                      Container(
                          alignment: Alignment.centerLeft,
                          child: const Text(
                            'tags',
                            style: TextStyle(color: Colors.grey),
                          )),
                      const SizedBox(height: 8),
                      Container(
                          alignment: Alignment.centerLeft,
                          child: const Text('headline')),
                    ],
                  ),
                )
              ],
            ),
          );
        },
        separatorBuilder: (BuildContext context, int index) => const Divider(),
      ),
      floatingActionButton: const FloatingActionButton(
        onPressed: null,
        tooltip: 'Search',
        child: Icon(Icons.search),
      ),
    );
  }
```
実行するとこんな感じ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3077916/ce80f618-e0c5-c3d9-ac4f-46223adea592.png" width="160" height="320" />

土台は出来たので次回API取得したデータをこれに反映させてみたいと思います

https://qiita.com/t0yger/items/2d65ad3bd66154fd2883