Flutterを触るときにこれは知っておきたい！！こと

# 最低限知っておきたい実装方法
Flutterを使ってモバイルをアプリを実装するうえで、「最低限これだけは知っておきたい実装」を網羅しておく。
「ここの内容を組み合わせれば、どんなものでも作れる」というレベルになるまでブラッシュアップしていきたい。

## ルーティング
今回記載しているのは、いわゆる「名前付きルート」という実装方法。
MaterialAppのプロパティである**routes**に、名称と実際に表示したいウィジェットを定義する。
以下の場合、「/top」という名称を指定したときに「TopPageウィジェット」を表示する。

```dart
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      initialRoute: '/',
      routes: <String, WidgetBuilder>{
        '/': (BuildContext context) =>
            MyHomePage(title: 'Flutter Demo Home Page'),
        '/top': (BuildContext context) => TopPage()
      },
    );
  }
```

## ページ遷移
ページ遷移の処理は、**スタックによるpushとpop**をイメージする。
次のページに遷移するときは、pushNamedで名称を指定して遷移。
前のページに戻るときは、popで戻る。

```dart
// 「/top」を指定してページ遷移
Navigator.of(context).pushNamed('/top',
  arguments: new MyPageArguments(
    name: this._name!,
    mailAddress: this._mailAddress!));

// 前のページに戻る
Navigator.of(context).pop();
```

ページ遷移する際に、次のページに引数として値を渡すことができる。
今回の例の場合は複数の値(name, mailAddress)を渡すため、
MyPageArgumentsクラスを定義して受け渡しに利用している。

```dart
class MyPageArguments {
  final String name;
  final String mailAddress;

  MyPageArguments({required this.name, required this.mailAddress});
}

// 引数を受け取る
ｆinal MyPageArguments args = ModalRoute.of(context)!.settings.arguments as MyPageArguments;
String _name = args.name
```

## 入力フォーム
**Formクラス**を利用する。
Formクラスは、TextFieldなどをグループ化してくれる。
ポイントは後ほど解説。

```dart:
final _form = GlobalKey<FormState>();
String? _name;
String? _mailAddress;
String? _password;
```

```dart:フォーム全体
Form(
  key: _form,
  child: Column(
    children: <Widget>[
      new TextFormField(
        enabled: true,
        maxLength: 10,
        style: TextStyle(color: Colors.red),
        obscureText: false,
        validator: (value) {
          if (value!.isEmpty) {
            return 'Please provide a value.';
          }
          return null;
        },
        onSaved: (String? value) {
          _userId = value;
        },
      ),
      new TextFormField(
        enabled: true,
        style: TextStyle(color: Colors.red),
        obscureText: false,
        validator: (value) {
          if (value!.isEmpty) {
            return 'Please provide a value.';
          }
          return null;
        },
        onSaved: (String? value) {
          _mailAddress = value;
        },
      ),
      new TextFormField(
          enabled: true,
          maxLength: 10,
          style: TextStyle(color: Colors.black),
          obscureText: true,
          maxLines: 1,
          onSaved: (String? value) {
            _password = value;
          }),
      ElevatedButton(
        child: const Text('Button'),
        style: ElevatedButton.styleFrom(
          primary: Colors.orange,
          onPrimary: Colors.white,
        ),
        onPressed: () {
          if (_form.currentState!.validate()) {
            _form.currentState!.save();
            Navigator.of(context).pushNamed('/top',
                arguments: new MyPageArguments(
                    name: this._name!,
                    mailAddress: this._mailAddress!));
          }
        },
      ),
    ],
  )
)
```

### バリデーション
バリデーションは、各TextFormFieldのvalidatorプロパティに定義する。
autovalidateModeに**onUserInteraction**を指定することで、ユーザ入力時にリアルタイムにバリデーションチェックを行う。

```dart
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
  if (value!.isEmpty) {
    return 'Please provide a value.';
  }
  return null;
},
```

以下のように、バリデーションエラーがない場合に次のページに遷移させる。

```dart
if (_form.currentState!.validate()) {
  _form.currentState!.save();
  Navigator.of(context).pushNamed('/top',
    arguments: new MyPageArguments(
      name: this._name!,
      mailAddress: this._mailAddress!));
}
```

### Formの内容を保存
FormStateインスタンスが持つsaveメソッドにより、入力されたFormの内容を保存する。
保存時に各TextFormFieldのonSavedが実行されるため、この中でプライベート変数に値を設定している。

```dart
// 保存
_form.currentState!.save();

// onSavedが呼び出される
onSaved: (String? value) {
  _userId = value;
},
```


## 今後追記する予定の内容
- StatefulWidgetのライフサイクル