[Flutter]最初のFlutterアプリを作るpart2-ドキュメント翻訳

## はじめに
こちらの翻訳となります。
https://codelabs.developers.google.com/codelabs/first-flutter-app-pt2/#0

Flutterは、記録的な速さでiOSとAndroid上で高品質のネイティブインターフェースを作成するためのGoogleのモバイルSDKです。
Flutterは既存のコードで動作し、世界中の開発者や組織によって使用されており、フリーでオープンソースです。

このコードラボでは、基本的なFlutterアプリを拡張してインタラクティブな機能を追加します。 
また、ユーザーが遷移できる2番目のページ（ルートと呼ばれる）も作成します。 
最後に、アプリのテーマ（色）を変更します。 
このコードラボはpart1「[遅延ロードリストの作成](https://qiita.com/gkn/items/af98200d7a98c033b597)」を拡張したものですが、
part2から始めたい場合でも開始できるようにコードを提供します。

### part2で学ぶこと
- iOSとAndroidの両方で自然に見えるFlutterアプリの書き方
- 迅速な開発サイクルのためのホットリロードの使用
- StatefulWidgetにインタラクティブな機能を追加する方法
- 2番目の画面を作成して遷移する方法
- テーマを使用してアプリの外観を変更する方法

### part2で構築するもの
スタートアップ企業の名前を生成する簡単なモバイルアプリからスタートしましょう。
ユーザーは名前を選択および選択解除して最良の名前を保存することができます。
AppBarの右上にあるリストアイコンをタップすると、
お気に入りの名前だけが一覧表示される新しいページ（ルートと呼ばれる）に遷移します。


アニメーションGIFは完成したアプリがどのように機能するかを示します。

![b17de15fa7831a1c.gif (993.7 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/14/47199/00bcaf6f-3462-4693-9754-00419c5588b8.gif)


## Flutter環境をセットアップする
part1を完了していない場合は、[最初のFlutterアプリを作るpart1](https://qiita.com/gkn/items/af98200d7a98c033b597)の「[Flutter環境をセットアップする](https://qiita.com/gkn/items/af98200d7a98c033b597#flutter%E7%92%B0%E5%A2%83%E3%82%92%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B)」を参照して、
Flutter開発のための環境をセットアップしてください。

## 始めるためのアプリを入手する
コードラボpart1を行なっていた場合は、既に始めるためのアプリケーションstartup_namerがあるので 
次のステップに進むことができます。

startup_namerがなくても大丈夫です。
次の手順で入手できます。

[最初のFlutterアプリの使用方法](https://flutter.dev/docs/get-started/test-drive?tab=vscode#create-app)の手順に従って、シンプルなテンプレートを作成します。
プロジェクトに（myappではなく）startup_namerという名前を付けます。

`lib / main.dart`からすべてのコードを削除し、このファイルのコードに置き換えます。
[このファイル](https://github.com/flutter/codelabs/blob/b3293b5bb0c0187bdbe8112f7759f4d75f4c040a/startup_namer/step4_infinite_list/lib/main.dart)には、名前の候補を生成し、無限リストとして表示するプログラムがあります。

以下に示すように、English Wordsパッケージを追加して`pubspec.yaml`を更新します。

``` yaml
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  english_words: ^3.1.0    // Add this line.
```

このEnglish Words packageは、名前として使用されるランダムな単語のペアを生成します。

Android Studioのエディタビューでpubspecを表示して、右上の「Packages get 」をクリックします。
 これでパッケージがプロジェクトに取り込まれます。 
コンソールには次のように表示されます。

``` console
flutter packages get
Running "flutter packages get" in startup_namer...
Process finished with exit code 0
```
アプリを実行してください。 
あなたが望むところまでスクロールしてみてください、絶え間なく名前のリストが表示されます。

## リストにアイコンを追加する
この手順では、各行にハートのアイコンを追加します。
 次のステップでは、それらをタップ可能にしてお気に入りを保存します。

RandomWordsStateに`_saved`のSet を追加します。
このSetは、ユーザーが好んだ単語の組み合わせを格納します。
 正しく実装されたSetは重複した値を許可しないため、ここではListよりもSetが使われることが多いです。

```dart
class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final Set<WordPair> _saved = Set<WordPair>();   // この行を追加
  final TextStyle _biggerFont = TextStyle(fontSize: 18.0);
  ...
}
```

`_buildRow`関数で、単語の組み合わせが既にお気に入りに追加されていないことを確認するためにalreadySavedを追加します。

```dart
Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);   // この行を追加
  ...
}
```

`_buildRow()`では、ListTileオブジェクトにハート型のアイコンを追加してお気に入りを有効にすることもできます。 
次のステップでは、ハートのアイコンとやり取りをする機能を追加します。

以下のようにアイコンを追加します。

```dart
Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(   // この行から
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),                // この行まで追加
  );
}
```

アプリをホットリロードします。 
各行にハートが表示されますが、まだインタラクティブではありません。

|android | iOS |
| ------------ | ------------- |
| ![b01521bf7a6e9f61.png (173.1 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/b65861a5-731f-49e4-a0c0-fb57cb7445fb.png) | ![eca56f73115e3550.png (73.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/5e339c58-8538-46b0-b47f-1d71af71a661.png) |

#### 順調ですか？
アプリが正しく実行されない場合は、入力ミスを探してみてください。 
必要に応じて、以下のリンクのコードを使用してください。
- [lib / main.dart](https://github.com/flutter/codelabs/blob/master/startup_namer/step5_add_icons/lib/main.dart)


## インタラクティブな機能を追加する
このステップでは、ハートのアイコンをタップ可能にします。 
ユーザーがリスト内の項目をタップしてその「お気に入り」状態を切り替えると、
単語の組み合わせが保存されたお気に入りのSetに追加または削除されます。

これを行うには、`_buildRow`関数を変更します。 
単語がすでにお気に入りに追加されている場合は、もう一度タップするとお気に入りから削除されます。 
Tileがタップされると、`setState()`を呼び出して状態が変化したことをフレームワークに通知します。

次に示すように、onTapを追加します。

```dart
Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {      //ここから9行追加します.
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else { 
          _saved.add(pair); 
        } 
      });
    },               // ここまで
  );
}
```

Tip： Flutterのリアクティブスタイルのフレームワークでは、`setState()`を呼び出すと、
Stateオブジェクトのbuild()メソッドが呼び出され、その結果、UIが更新されます。

アプリをホットリロードします。 
あなたは名前をお気に入りにする、または名前をお気に入りから外すために任意のTileをタップすることができるはずです。
 Tileをタップすると、タップポイントから発生する暗黙のインクスプラッシュアニメーションが生成されます。

|android | iOS |
| ------------ | ------------- |
|![8caedd467e066f03.png (172.8 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/b8660c65-3a0c-4173-b9d3-d2bdadd6d849.png)|![9d55495e865ccdaf.png (84.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/4e612b8a-7b68-4154-ba85-92b47e40d869.png)|

#### 順調ですか？
アプリが正しく実行されない場合は、入力ミスを探してみてください。 
必要に応じて、以下のリンクのコードを使用してください。
- [lib / main.dart](https://github.com/flutter/codelabs/blob/master/startup_namer/step6_add_interactivity/lib/main.dart)


## 新しい画面に遷移する
このステップでは、お気に入りを表示する新しいページ（Flutterではルートと呼ばれる）を追加します。 
ホームルートと新しいルートの間を遷移する方法を学びます。

Flutterでは、Navigatorがアプリのルートを含むスタックを管理します。
ルートをNavigatorのスタックにプッシュすると、そのルートに表示が更新されます。 
Navigatorのスタックからルートをポップすると、前のルートに表示が戻ります。

次に、RandomWordsStateのbuildメソッドでAppBarにリストアイコンを追加します。 
ユーザーがリストアイコンをクリックすると、保存されたお気に入りが表示される新しいルートがNavigatorにプッシュされ、
アイコンが表示されます。

アイコンとそれに対応するアクションを`build`メソッドに追加します。

```dart
class RandomWordsState extends State<RandomWords> {
  ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: <Widget>[      // ここから3行追加してください
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
        ],                      // ここまで
      ),
      body: _buildSuggestions(),
    );
  }
  ...
}
```

Tip： 一部のwidgetプロパティは一個のwidget（`child`）を取り、
アクションなどの他のプロパティは角括弧（`[]`）で示されるように、配列のwidget（`child`）を取ります。

RandomWordsStateクラスに`_pushSaved()`関数を追加します。

```dart
  void _pushSaved() {
  }
```

アプリをホットリロードします。 
リストアイコン（![e401ba8d3a9e2379.png (1.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/96b5a0b3-5fcf-4eea-8520-80eb418fa12b.png)）がAppBarに表示されます。
` _pushSaved`関数は空なので、タップしても何も起こりません。

次に、ルートを作成してそれをNavigatorのスタックにプッシュします。
 この操作により、新しいルートを表示するように画面が変わります。
 新しいページのコンテンツは、無名関数のMaterialPageRouteの`builder`プロパティに組み込まれています。


次に示すように、`Navigator.push`を呼び出します。
これにより、ルートがNavigatorのスタックにプッシュされます。
 IDEは無効なコードについてwarningを出しますが、次のセクションでそれを修正します。

```dart
void _pushSaved() {
  Navigator.of(context).push(
  );
}
```

次に、MaterialPageRouteとそのbuilderを追加します。 
ここでは、ListTileを生成するコードを追加します。
 ListTileの`divideTiles()`メソッドは、各ListTileの間に水平方向の間隔を追加します。 
`divided`変数は、便利な関数`toList()`によってリストに変換された最終行を保持します。

以下のようにコードを追加します。

```dart
void _pushSaved() {
  Navigator.of(context).push(
    MaterialPageRoute<void>(   //ここから20行追加してください
      builder: (BuildContext context) {
        final Iterable<ListTile> tiles = _saved.map(
          (WordPair pair) {
            return ListTile(
              title: Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );
        final List<Widget> divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
          .toList();
      },
    ),                       //ここまで
  );
}
```

builderプロパティは、 "Saved Suggestions"という名前の新しいルート、Scaffoldを返します。
新しいルートの本体は、ListTilesを含むListViewで構成されています。 各行はdividerで区切られています。

```dart
void _pushSaved() {
  Navigator.of(context).push(
    MaterialPageRoute<void>(
      builder: (BuildContext context) {
        final Iterable<ListTile> tiles = _saved.map(
          (WordPair pair) {
            return ListTile(
              title: Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );
        final List<Widget> divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
              .toList();

        return Scaffold(         // ここから6行追加してください
          appBar: AppBar(
            title: Text('Saved Suggestions'),
          ),
          body: ListView(children: divided),
        );                       // ここまで
      },
    ),
  );
}
```

アプリをホットリロードします。 
いくつかお気に入りにして、AppBarのリストアイコンをタップします。 
お気に入りを含む新しいルートが表示されます。 
 NavigatorがAppBarに「戻る」ボタンを追加していることに注目してください。
 Navigator.popを明示的に実装する必要はありませんでした。
 戻るボタンをタップしてホームルートに戻ります。

|iOS  - メインルート | iOS  - Saved suggestionsルート |
| ------------ | ------------- |
|![6e06cd704eec2745.png (83.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/1d014d23-8e03-4167-ab40-934f9628f2b1.png)|![a9f9050220d86dad.png (56.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/c132a147-4c4f-4385-ae89-8bea33225b01.png)|

#### 順調ですか？
アプリが正しく実行されない場合は、入力ミスを探してみてください。 
必要に応じて、以下のリンクのコードを使用してください。
- [lib / main.dart](https://github.com/flutter/codelabs/blob/master/startup_namer/step7_navigate_route/lib/main.dart)


## テーマを使用してUIを変更する
このステップでは、アプリのテーマを変更します。
テーマは、アプリの外観を制御します。 
物理デバイスまたはエミュレータに依存するデフォルトのテーマを使用することも、
ブランドを反映するようにテーマをカスタマイズすることもできます。

[ThemeData](https://docs.flutter.io/flutter/material/ThemeData-class.html)クラスを設定することで、アプリのテーマを簡単に変更できます。 
このアプリは現在デフォルトのテーマを使用していますが、アプリの基本色を白に変更します。

MyAppクラスの色を変更します。

```dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: ThemeData(          //ここから3行を追加します
        primaryColor: Colors.white,
      ),                         // ここまで
      home: RandomWords(),
    );
  }
}
```

アプリをホットリロードします。 
背景全体が白になり、AppBarも表示されます。

演習として、ThemeDataを使用してUIを他のテーマに変更してください。
マテリアルライブラリの[Colors](https://docs.flutter.io/flutter/material/Colors-class.html)クラスにはたくさんの色の組み合わせが準備されています。
そして、ホットリロードを使うことでUIを素早く簡単に試すことができます。

|android | iOS |
| ------------ | ------------- |
|![a8a58e812150f3c.png (168.9 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/8efe5f03-b107-487d-b82c-635ac8993bf1.png)|![2ae336b38fe4c72a.png (76.4 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/15/47199/d2378333-5f80-4b53-b550-62f7d2aa8ff2.png)|

#### 順調ですか？
アプリが正しく実行されない場合は、入力ミスを探してみてください。 
必要に応じて、以下のリンクのコードを使用してください。
- [lib / main.dart](https://github.com/flutter/codelabs/blob/master/startup_namer/step8_themes/lib/main.dart)


## おめでとう！

あなたは、iOSとAndroidの両方で動作するインタラクティブなFlutterアプリを完成させました。
 このコードラボでは、
- Dartでコードを書きました。
- 開発サイクルを短縮するためにホットリロードを使用しました。
- ステートフルなwidgetを実装して、アプリにインタラクティブ機能を追加しました。
- ルートを作成し、ホームルートと新しいルートの間を遷移するためのロジックを追加しました。
- テーマを使用してアプリのUIを変更することについて学習しました。

誤字や、分かりにく箇所などありましたらご連絡お願いします。