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

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

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

このコードラボでは、簡単なFlutterアプリを作成します。
オブジェクト指向コードや、変数、ループ、条件付きなどの基本的なプログラミング概念に精通している場合は、このコードラボを完成させることができます。
Dartやモバイルプログラミングに関するこれまでの経験は必要ありません。

### part1で学ぶこと
- iOSとAndroidの両方で自然に見えるFlutterアプリの書き方
- Flutterアプリの基本構造
- 機能を拡張するためのパッケージの検索と使用
- 迅速な開発サイクルのためのホットリロードの使用
- ステートフルウィジェットを実装する方法
- 無限の、遅延ロードされたリストを作成する方法。

コードラボのpart2では、インタラクティブな機能を追加し、アプリのテーマを変更し、新しいページに移動する機能（Flutterではルートと呼ばれる）を追加します。

### part1で構築するもの
あなたはスタートアップ企業の名前を生成する簡単なモバイルアプリを実装するとしましょう。
ユーザーは名前を選択および選択解除して最良の名前を保存することができます。
このコードは一度に10個の名前を生成します。
ユーザーがスクロールすると、新しい名前が生成されます。
ユーザーは永遠にスクロールでき、新しい名前が次々に生成されます。

part1で完成するアプリがどのように機能するかGIFで表示しています。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3130343837322f37343939346137652d646163312d323539622d313862662d3564626630386562613134622e676966.gif (1.0 MB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/f6f5e1d2-e219-456a-9370-2c09ab1ed9a0.gif)


## Flutter環境をセットアップする
このチュートリアルを行うには、[Flutter SDK ](https://flutter.dev/docs/get-started/install)とエディタの 2つのソフトウェアが必要です。
このコードラボはAndroid Studioを想定していますが、好みのエディタを使用できます。

このコードラボは、以下のデバイスを使用して実行できます。
- コンピュータに接続された物理デバイス（AndroidまたはiOS）。
- iOSのシミュレーター。（Xcodeツールをインストールする必要があります。）
- Androidのエミュレータ。（Android Studioでの設定が必要です。）

## 最初のFlutterアプリを作成する
[最初のFlutterアプリ ](https://flutter.dev/docs/get-started/test-drive?tab=vscode#androidstudio)の手順に従って、シンプルなFlutterアプリを作成します。
プロジェクトにstartup_namerという名前を付けます。
このプロジェクトを変更していきます。

Tip： IDEのオプションとして "New Flutter Project"が表示されない場合は、FlutterとDart用のプラグインがインストールされていることを確認してください。

このコードラボでは、Dartコードが存在するlib / main.dartを編集していきます。

```lib / main.dart```の内容を置き換えます。
lib / main.dartからすべてのコードを削除します。 
画面中央に「Hello World」と表示されるように次のコードに置き換えます。

```dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: const Center(
          child: const Text('Hello World'),
        ),
      ),
    );
  }
}
```

Tip： コードをアプリに貼り付けると、インデントがずれることがあります。
IDEではこれを自動的に修正することができます。
- Android Studio / IntelliJ IDEA：dartコードを右クリックして、[ dartfmtでコードを再フォーマット ]を選択します。
- VSコード：右クリックして[ 文書の書式設定]を選択します。
- ターミナル：ファイル名を指定して実行```flutter format <filename>```。

 アプリを実行してください。
デバイスに応じて、AndroidまたはiOSのどちらかの出力が表示されるはずです。

|android | iOS |
| ------------ | ------------- |
| ![6b18b6e158b15685.png (149.8 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/01433b71-6d0f-4514-ac3f-482a99199b55.png) | ![2e973d40d6e82114.png (44.7 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/e3f088d0-0652-4037-887f-a8b27f5177ac.png) |

Tip： 初めて物理デバイスを実行するときは、ロードに時間がかかることがあります。
これが終わったら、ホットリロードを使って素早く更新ができます。
アプリ実行中に保存を行なった場合は、ホットリロードも実行されます。

#### 注目
- この例ではマテリアルアプリを作成します。
 [マテリアル](https://material.io/design/)は、モバイルおよびWebで標準的なビジュアルデザイン言語です。 
Flutterは豊富なMaterialウィジェットを提供しています。
- メインメソッドは矢印（=>）表記を使います。
ワンラインの関数またはメソッドにはアロー表記を使います。
- アプリはStatelessWidgetを拡張し、アプリ自体をウィジェットにします。
 Flutterでは、配置、パディング、レイアウトなど、ほとんどすべてがウィジェットです。
- マテリアルライブラリのScaffoldウィジェットは、デフォルトのアプリケーションバー、タイトル、およびホーム画面のウィジェットツリーを保持するbodyプロパティを提供します。
ウィジェットのサブツリーはかなり複雑になる可能性があります。
- ウィジェットの主な仕事は、他の下位レベルのウィジェットに関してウィジェットを表示する方法を記述する`build`メソッドを提供することです。

## 外部パッケージを使用する
このステップでは、[english_words](https://pub.dartlang.org/packages/english_words)という名前のオープンソースパッケージを使用します。
このパッケージには、最も使用頻度の高い数千語の単語といくつかのユーティリティ関数が含まれています。

[Pubサイト](https://pub.dartlang.org/flutter/)ではenglish_wordsパッケージや他の多くのオープンソースパッケージを見つけることができます。

pubspecファイルは、Flutterアプリのアセットを管理します。 
pubspec.yamlで、`english_words：^ 3.1.0`（english_words 3.1.0以降）を依存関係リストに追加します。

```yaml
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  english_words: ^3.1.0   # この行を追加
```
Android Studioのエディタービューでpubspecを表示して、[Packages get]の順にクリックします。 
これでパッケージがプロジェクトに取り込まれコンソールに次のように表示されます。
```console
flutter packages get
Running "flutter packages get" in startup_namer...
Process finished with exit code 0
```
lib / main.dartに新しいパッケージをインポートします。
```dart
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';  // この行を追加
```
入力すると、Android Studioからインポートするライブラリの候補が表示されます。 
インポート文字列が灰色になり、インポートされたライブラリが未使用であることがわかります。

次に、文字列 "Hello World"の代わりにenglish_wordsパッケージを使用してテキストを生成します。

```dart
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random(); // この行を追加
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(    // "const"を "new"に変更してください。
          //child: Text('Hello World'),   // このテキストを置き換えます。
          child: Text(wordPair.asPascalCase),  // このテキストも追加します。
        ),
      ),
    );
  }
}
```
Tip：  "Pascal case"（ "大文字キャメルケース"とも呼ばれます）は、文字列内の各単語が大文字で始まることを意味します。 
「アッパーキャメルケース」は「UpperCamelCase」になります。

アプリが実行中の場合は、ホットリロードボタン（![7f9a9e103c7b5e5.png (579 B)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/0e1b23c0-636c-4127-bc76-6aad4faf8338.png)）を使用して実行中のアプリを更新します。
 ホットリロードをクリックするかプロジェクトを保存するたびに、ランダムに選択された別の単語ペアが表示されます。 
これは、ペアリングされた単語がbuildメソッド内で生成されるためです。
アプリがレンダリングをするか、Flutter Inspectorでプラットフォームを切り替えるときに実行されます。

|android | iOS |
| ------------ | ------------- |
|![93ba69e20e109c24.png (150.5 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/3f41652e-5505-45ce-8d7d-cc69a086cb43.png)|![35f55fd09f2ff2d9.png (44.5 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/05/47199/e19f9a28-8c50-4a06-9e88-e76e1c474734.png)|

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

## StatefulWidgetを追加する
StatelessWidgetは変更されないものです。
つまり、プロパティは変更できません。

StatefulWidgetは、ウィジェットの有効期間中に変更される可能性がある状態を維持します。 
StatefulWidgetを実装するには、少なくとも2つのクラスが必要です。
1）Stateクラス
2）StatefulWidgetクラス

このステップでは、StatefulWidgetのRandomWordsを追加します。
このStateクラスはRandomWordsStateを作成します。 
その後、既存のMyAppステートレスウィジェット内の子としてRandomWordsを使用します。
そして、StatelessWidgetの中に child として追加します。

まず、最小状態クラスを作成します。 
`MyApp`の外部ファイルのどこにでも置くことができますが、今回はファイルの末尾に追加します。
 次のテキストを追加してください。

```dart
class RandomWordsState extends State<RandomWords> {
  // TODO ビルドメソッド追加
}
```
State \<RandomWords>に注目してください。 
これは、RandomWordsでの使用に特化した汎用のStateクラスを作成しています。
 アプリのロジックとステートの大部分はここになっていきます。
ここでRandomWordsウィジェットの状態を維持します。 
このクラスは生成された単語を保存していきます。ま無限スクロールできるように追加していきます。
part2では、ユーザーがお気に入りを追加、削除できるようにしてリストを作成できるようにしていきます。

RandomWordsStateはRandomWordsクラスに依存します。

RandomWordsウィジェットをmain.dartに追加します。 
RandomWordsウィジェットは、Stateクラスを作成すること以外にはほとんど何もしません。

```dart
class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}
```
ステートクラスを追加したら、ビルドして確認してみましょう。
 次に、単語生成コードをMyAppからRandomWordsStateに移動して単語ペアを生成する基本的な構築方法を追加します。

`build`メソッドをRandomWordsStateに追加します。

```dart
class RandomWordsState extends State<RandomWords> {
  @override                                  // この行から
  Widget build(BuildContext context) {
    final WordPair wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }                                          // この行まで追加
}
```

以下のように変更して、MyAppから単語生成コードを削除します。

```dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final WordPair wordPair = WordPair.random();  // この行を削除してください。

    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          //child: Text(wordPair.asPascalCase), // この行を変更
          child: RandomWords(),                 // これに変更
        ),
      ),
    );
  }
}
```
アプリをホットリロードします。
これまでと同じように動作し、ホットリロードまたは保存するたびに単語の組み合わせが表示されます。

Tip： ホットリロード時に次の警告が表示された場合は、アプリを再起動してみてください。

```
Reloading...
Not all changed program elements ran during view reassembly; consider restarting.
```
再起動すると、変更内容がアプリのUIに反映されます。

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

## 無限スクロールのListViewを作成します
このステップでは、RandomWordsStateを展開して単語ペアのリストを生成して表示します。
ユーザーがスクロールすると、リスト（ListViewウィジェットに表示される）は無限に生成されていきます。。 
ListViewの`builder`ファクトリコンストラクターを使用すると、必要に応じてリストビューを[遅延的](https://ja.wikipedia.org/wiki/%E9%81%85%E5%BB%B6%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)に構築できます。

候補にでてきた単語の組み合わせを保存するために、_suggestionsリストをRandomWordsStateクラスに追加します。 
また、フォントサイズを大きくするために_biggerFont変数を追加してください。

Tip： アンダースコアを識別子の前に付けると、Dart言語ではprivateになります。

```dart
class RandomWordsState extends State<RandomWords> {
  // 次の2行を追加してください。
  final List<WordPair> _suggestions = <WordPair>[];
  final TextStyle _biggerFont = const TextStyle(fontSize: 18); 
  ...
}
```

次に、`_buildSuggestions（）`関数をRandomWordsStateクラスに追加します。 
このメソッドは、単語の組み合わせを表示するListViewを構築します。

ListViewクラスは、ビルダープロパティ`itemBuilder`を提供します。
これはファクトリビルダーであり、無名関数として指定されたコールバック関数です。
 BuildContextと行イテレータの2つのパラメータが関数に渡されます。
イテレータ`i`は0から始まり、関数が呼び出されるたびに（単語の組み合わせごとに1回ずつ）増分します。
 このモデルでは、ユーザーがスクロールするにつれて候補リストを無限に増やすことができます。

以下に示す_buildSuggestions関数全体をRandomWordsStateクラスに追加します（必要に応じてコメントを削除します）。

```dart
  Widget _buildSuggestions() {
    return ListView.builder(
      padding: const EdgeInsets.all(16),
      // itemBuilderコールバックは、単語のペアリングごとに1回呼び出され、
      // 各単語をListTileに配置します。
      // 偶数行の場合、この関数はペアリングされた単語をListTileに追加します。
      // 奇数行の場合、この関数はリストを視覚的に区切るための
      // Dividerウィジェットを追加します。
      // Dividerは小型デバイスでは見づらい場合があります。
      itemBuilder: (BuildContext _context, int i) {
        // ListViewの各行の前に1ピクセルの高さの
        // 仕切りウィジェット(Divider)を追加します。
        if (i.isOdd) {
          return Divider();
        }

        // 構文 "i〜/ 2"は、iを2で除算して整数の結果を返します。
        // 例えば、iが1、2、3、4、5の場合は0、1、1、2、2となります。
        // これは、ListView内の実際の単語の組み合わせ数から、
        //仕切りウィジェットを差し引いた数を計算します。
        final int index = i ~/ 2;
        // 利用可能な単語の組み合わせの終わりに達した場合は...
        if (index >= _suggestions.length) {
          // ...さらに10個生成し、それらを候補リストに追加します。
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      }
    );
  }
```

`_buildSuggestions`関数は、単語ペアごとに1回`_buildRow`を呼び出します。 
この関数はListTileに新しい単語の組み合わせをそれぞれ表示します。
これにより、part2でより魅力的に拡張することができます。

RandomWordsStateに`_buildRow`関数を追加します。

```dart
  Widget _buildRow(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }
```

RandomWordsStateの`build`メソッドを更新して、単語生成ライブラリを直接呼び出すのではなく、
`_buildSuggestions（）`を使用するようにします。 （Scaffoldは基本的なマテリアルデザインのレイアウトを実装します。）

```dart
  @override
  Widget build(BuildContext context) {
    //final wordPair = WordPair.random(); // これら2行を削除してください。
    //return Text(wordPair.asPascalCase); 

    return Scaffold (                   //この行から
      appBar: AppBar(
        title: Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(),
    );                                      // この行まで追加
  }
```

MyAppの`build`メソッドを更新します。
titleを変更し、homeをRandomWordsウィジェットに変更します。

```dart
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
```

アプリをリスタートしてください。 
どれだけスクロールしても、単語の組み合わせのリストが表示されます。

|android | iOS |
| ------------ | ------------- |
|![1423ec5220b287e7.png (168.2 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/06/47199/3257ba19-b37c-41d5-93e3-932900d6d42b.png)|![d71590c8c3c2e6f8.png (73.0 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/06/47199/6be84fb3-1b24-4530-a285-67dbd98b1cee.png)|

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


## 次のステップ
### おめでとうございます。
コードラボのpart1が完成しました。
このアプリを拡張したい場合は、part2に進んでください。
part2では、アプリを次のように変更します。
- インタラクティブな機能を追加します。
- 新しいルートに移動する機能を追加します。
- テーマカラーを変更します。
![b17de15fa7831a1c.gif (993.7 kB)](https://img.esa.io/uploads/production/attachments/8530/2019/05/06/47199/54d0a5db-d228-44d1-b78c-6941b9693aa9.gif)


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