Flutterの画面遷移(Navigator)をエフェクトを使ってかっこよく、コードはスッキリさせたい

## 発生した問題

1. FlutterのNavigatorはデフォルトだと下から上へのスライドしかない(フェードや横のスライドを入れたい)
2. Routeの設定をMaterialAppに記載していくと、MaterialAppの中身が肥大化する。

### 作成したコードのイメージ

```Dart:main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('ja', 'JP'),
      ],
      theme: ThemeData(
        primarySwatch: Colors.brown,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      // ここに定義することで、
      // Navigator.of(context).pushNamed("/aaa");
      // で遷移できるが、MaterialAppが長くなることに加えて、
      // 下から上への画面遷移になってしまうのが嫌だ。
      routes: <String, WidgetBuilder>{
        '/aaa': (_) => new AAA(),
        '/bbb': (_) => new BBB(),
        '/ccc': (_) => new CCC(),
      },
      home: MyHomePage(title: 'My App'),
    );
  }
}
```

## 環境

- macOS Catalina 10.15.4
- Android Studio 3.6.1
- Flutter 1.17.0

## 結論

### 1. FlutterのNavigatorはデフォルトだと下から上へのスライドしかない(フェードや横のスライドを入れたい)

[page_transition](https://pub.dev/packages/page_transition)を使うことで解決しました。

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  page_transition: ^1.1.5
```

```
$ flutter pub get
```

```Dart:main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('ja', 'JP'),
      ],
      theme: ThemeData(
        primarySwatch: Colors.brown,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      // ここ
      // Navigator.of(context).pushNamed("/aaa");
      // で遷移できることに加えて、遷移のエフェクトを設定できる。
      // しかしながら、MaterialAppがさらに長くなってしまった。
      onGenerateRoute: (settings) {
       switch (settings.name) {
        // よく見る右から左へ画面遷移するパターン
        case '/aaa':
          return PageTransition(
            child: AAA(),
            type: PageTransitionType.rightToLeft,
            settings: settings,
          );
          break;
        // じんわりフェードで画面遷移するパターン
        case '/bbb':
          return PageTransition(
            child: BBB(),
            type: PageTransitionType.fade,
            settings: settings,
          );
          break;
        // Navigatorのデフォルト遷移パターン
        case '/ccc':
          return PageTransition(
            child: CCC(),
            type: PageTransitionType.downToUp,
            settings: settings,
          );
          break;
        default:
          return null;
　　　　}
      }
      home: MyHomePage(title: 'My App'),
    );
  }
}
```

このほかにもエフェクトが使えるので、[page_transition](https://pub.dev/packages/page_transition)を見てみてください。

### 2. Routeの設定をMaterialAppに記載していくと、MaterialAppの中身が肥大化する。

他のLaravelやNuxtのようにRouterファイルとして切り出しました。
まずは、`router.dart` というファイルでrouteとエフェクトを定義してから、

```dart:router.dart
import 'package:flutter/material.dart';
import 'package:page_transition/page_transition.dart';
// 適宜呼びたいページをimportしてください

mixin PageRouter implements StatelessWidget {

  static Route generate (RouteSettings settings) {
     switch (settings.name) {
        // よく見る右から左へ画面遷移するパターン
        case '/aaa':
          return PageTransition(
            child: AAA(),
            type: PageTransitionType.rightToLeft,
            settings: settings,
          );
          break;
        // じんわりフェードで画面遷移するパターン
        case '/bbb':
          return PageTransition(
            child: BBB(),
            type: PageTransitionType.fade,
            settings: settings,
          );
          break;
        // Navigatorのデフォルト遷移パターン
        case '/ccc':
          return PageTransition(
            child: CCC(),
            type: PageTransitionType.downToUp,
            settings: settings,
          );
          break;
        default:
          return null;
    }
  }
}
```

`main.dart` で作成したクラスメソッドを呼び出すだけでOK

```dart:main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('ja', 'JP'),
      ],
      theme: ThemeData(
        primarySwatch: Colors.brown,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      // ここで呼び出すだけでOK!
      onGenerateRoute: PageRouter.generate
      home: MyHomePage(title: 'My App'),
    );
  }
}
```

今後、ページの追加がある時には`router.dart` を編集すればOKです。
何か修正点やもっといい案があればぜひコメント欄でください！