Open5

Flutter画面遷移の調査

muranakarmuranakar

MaterialPageRouteとは。。Routeとは。。RouteSettingsとは。。

これらに関連した単語をつらつらと調査していく。

muranakarmuranakar

MaterialPageRouteとは

MaterialPageRoute とは、画面全体を置き換えるモーダルルートで、プラットフォームに適応したトランジション(遷移アニメーション)を提供するクラスです。

主な特徴:

  1. プラットフォーム別の遷移アニメーション:

    • Android の場合:

      • 画面表示時:ズームインしながらフェードイン
      • 画面終了時:ズームアウトしながらフェードアウト
    • iOS の場合:

      • 基本動作:右からスライドイン(右から左へ)
      • 戻る時:左から右へスライド
      • 注:アラビア語など右から左に読む言語の場合は方向が逆になります
  2. 重要なプロパティ:

    • maintainState

      • true(デフォルト):前の画面をメモリに保持
      • false:メモリを解放
    • fullscreenDialog

      • true:フルスクリーンモーダルダイアログとして扱う
      • iOS の場合、画面下から上にアニメーション
    • barrierDismissible

      • true の場合:ESCキーで画面を閉じることが可能
      • 閉じる際の戻り値は null
  3. ジェネリック型 T

    • Navigator.pop で画面を閉じる際の戻り値の型を指定
    • 例:
    // String型の戻り値を期待する場合
    MaterialPageRoute<String>(
      builder: (context) => MyPage(),
    );
    

使用例:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailPage(),
    maintainState: true,  // 前の画面をメモリに保持
    fullscreenDialog: false,  // 通常の画面遷移として扱う
  ),
);

これは Flutter のマテリアルデザインに沿った標準的な画面遷移を実現するための最も一般的なルートクラスの1つです。画面遷移時のアニメーションが自動的にプラットフォームに適応するため、Android と iOS それぞれのプラットフォームでネイティブらしい自然な遷移を実現できます。

https://api.flutter.dev/flutter/material/MaterialPageRoute-class.html

muranakarmuranakar

Route<T> とは

簡単に伝えると
画面遷移の「どのように表示するか」
という部分を担当する要素です。

詳細

Route クラスは、Navigator によって管理される画面遷移のエントリを抽象化したクラスです。

主な特徴:

  1. 基本概念:

    • Navigator と「ルート」(画面遷移の単位)の間の抽象的なインターフェースを定義
    • 多くのルートは視覚的な要素を持ち、それらは Navigator の Overlay 内に OverlayEntry として配置される
  2. ジェネリック型 T

    • ルートの戻り値の型を指定
    • currentResult, popped, didPop メソッドで使用
    • 戻り値が不要な場合は void を指定可能
  3. Page との関係:

    • ルートは Page のサブクラスである settings を持つことができる
    • Page ベースのルート:
      • Navigator.pages の更新時に Page.createRoute から作成される
      • ルートの生存期間中に関連付けられた Page が変更される可能性がある
      • Page が更新された場合、Navigator は changedInternalState を呼び出してルートに通知

使用例:

// 基本的な使用例
class MyCustomRoute<T> extends Route<T> {
  
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    return MyCustomPage();
  }
}

// Navigator での使用
Navigator.push(
  context,
  MyCustomRoute<String>(),
);

カスタムルートの実装例:

class FadeRoute<T> extends Route<T> {
  FadeRoute({
    required this.builder,
    this.settings,
  });

  final WidgetBuilder builder;
  final RouteSettings settings;

  
  Color? get barrierColor => null;

  
  String? get barrierLabel => null;

  
  bool get maintainState => true;

  
  Duration get transitionDuration => Duration(milliseconds: 300);

  
  Widget buildPage(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
  ) {
    return FadeTransition(
      opacity: animation,
      child: builder(context),
    );
  }
}

主なユースケース:

  1. カスタム遷移アニメーションの実装:

    Navigator.push(
      context,
      FadeRoute(
        builder: (context) => DetailPage(),
      ),
    );
    
  2. 戻り値のある画面遷移:

    final result = await Navigator.push<String>(
      context,
      MyCustomRoute<String>(),
    );
    
  3. Page ベースのルート:

    Navigator(
      pages: [
        MaterialPage(
          key: ValueKey('home'),
          child: HomePage(),
        ),
        if (showDetails)
          MaterialPage(
            key: ValueKey('details'),
            child: DetailsPage(),
          ),
      ],
      onPopPage: (route, result) {
        if (!route.didPop(result)) {
          return false;
        }
        // ページの状態を更新
        return true;
      },
    );
    

このクラスは Flutter のナビゲーションシステムの基礎となる重要な抽象クラスで、画面遷移に関する基本的な動作を定義します。カスタムルートを作成する際は、このクラスを継承することで、独自の遷移アニメーションや動作を実装することができます。

https://api.flutter.dev/flutter/widgets/Route-class.html

muranakarmuranakar

RouteSettingsとは

ルート(画面)に関する追加情報を保持するためのクラスです。画面遷移時の設定や情報を管理します。

主なプロパティ:

  1. name (String?)

    • ルートの名前(画面を識別するための文字列)
    • URL のパス部分のようなもの
    RouteSettings(name: '/home')  // ホーム画面
    RouteSettings(name: '/details/123')  // ID:123の詳細画面
    
  2. arguments (Object?)

    • ルートに渡すデータ
    • 次の画面に情報を渡したい時に使用
    RouteSettings(
      name: '/user',
      arguments: {'userId': 123, 'userName': 'John'}
    )
    

使用例:

  1. 基本的な使い方
MaterialPageRoute(
  settings: RouteSettings(
    name: '/detail',
    arguments: {'id': 123},
  ),
  builder: (context) => DetailPage(),
)
  1. 引き渡されたデータの取得
class DetailPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    // 現在のルートの設定を取得
    final settings = ModalRoute.of(context)?.settings;
    
    // 引き渡されたデータを取得
    final args = settings?.arguments as Map<String, dynamic>;
    final id = args['id'];

    return Scaffold(
      appBar: AppBar(
        title: Text('詳細 #$id'),
      ),
      // ...
    );
  }
}
  1. 名前付きルートでの使用
MaterialApp(
  // ルート定義
  routes: {
    '/': (context) => HomePage(),
    '/detail': (context) => DetailPage(),
  },
  // 名前付きルートの使用
  onGenerateRoute: (settings) {
    if (settings.name == '/detail') {
      final args = settings.arguments as Map<String, dynamic>;
      return MaterialPageRoute(
        builder: (context) => DetailPage(),
        settings: settings,  // 設定を引き継ぐ
      );
    }
    return null;
  },
)

実践的な使用シーン:

  1. 画面間でのデータ受け渡し
// データを渡す側
Navigator.pushNamed(
  context,
  '/product',
  arguments: {
    'productId': '123',
    'productName': 'スマートフォン',
    'price': 50000,
  },
);

// データを受け取る側
class ProductPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final args = ModalRoute.of(context)!.settings.arguments 
                as Map<String, dynamic>;
    
    return Scaffold(
      appBar: AppBar(
        title: Text(args['productName']),
      ),
      body: Text('価格: ${args['price']}円'),
    );
  }
}
  1. 画面遷移の分析やログ取得
MaterialApp(
  navigatorObservers: [
    RouteObserver<PageRoute>(),
  ],
  onGenerateRoute: (settings) {
    // 画面遷移のログを記録
    print('画面遷移: ${settings.name}');
    print('パラメータ: ${settings.arguments}');
    
    // 通常のルート生成処理
    return MaterialPageRoute(
      settings: settings,
      builder: (context) {
        // ...
      },
    );
  },
)

このように、RouteSettings は画面遷移時の情報管理や、画面間でのデータのやり取りを簡単にする重要なクラスです。特に大規模なアプリケーションでは、画面遷移の管理やデータの受け渡しを整理するために非常に役立ちます。

https://api.flutter.dev/flutter/widgets/RouteSettings-class.html

muranakarmuranakar

ModalRoute とは?

画面上に別の画面やダイアログを表示する時に使う特別な仕組みです。

特徴

  • 前の画面を操作できないようにブロックします
  • 画面全体をカバーしますが、完全に隠す必要はありません
  • 戻り値を設定できます(例:「はい」「いいえ」の選択結果)

よくある使用例:

  1. 確認ダイアログ
// 「はい」「いいえ」で答える簡単なダイアログ
showDialog(
  context: context,
  builder: (context) => AlertDialog(
    title: Text('確認'),
    content: Text('保存しますか?'),
    actions: [
      TextButton(
        child: Text('いいえ'),
        onPressed: () => Navigator.pop(context, false),
      ),
      TextButton(
        child: Text('はい'),
        onPressed: () => Navigator.pop(context, true),
      ),
    ],
  ),
);
  1. 下から出てくるメニュー
// 下からスライドで表示されるメニュー
showModalBottomSheet(
  context: context,
  builder: (context) => Container(
    height: 200,
    child: Column(
      children: [
        ListTile(
          title: Text('写真を撮影'),
          onTap: () => Navigator.pop(context, 'camera'),
        ),
        ListTile(
          title: Text('ギャラリーから選択'),
          onTap: () => Navigator.pop(context, 'gallery'),
        ),
      ],
    ),
  ),
);
  1. データ入力フォーム
// データを入力するポップアップ
showDialog(
  context: context,
  builder: (context) => AlertDialog(
    title: Text('メモを追加'),
    content: TextField(
      decoration: InputDecoration(
        hintText: 'メモを入力してください',
      ),
    ),
    actions: [
      TextButton(
        child: Text('キャンセル'),
        onPressed: () => Navigator.pop(context),
      ),
      TextButton(
        child: Text('保存'),
        onPressed: () {
          // 入力されたテキストを返す
          Navigator.pop(context, '入力されたテキスト');
        },
      ),
    ],
  ),
);

使い方のポイント:

  1. 結果を受け取る
// ダイアログの結果を待って処理する
final result = await showDialog<bool>(
  context: context,
  builder: (context) => AlertDialog(
    title: Text('確認'),
    content: Text('削除しますか?'),
    actions: [
      TextButton(
        child: Text('いいえ'),
        onPressed: () => Navigator.pop(context, false),
      ),
      TextButton(
        child: Text('はい'),
        onPressed: () => Navigator.pop(context, true),
      ),
    ],
  ),
);

// 結果に応じて処理
if (result == true) {
  print('削除が選択されました');
} else {
  print('キャンセルされました');
}

ModalRoute は主に以下のような場面で使います:

  • ユーザーに確認を取りたい時
  • メニューを表示したい時
  • データを入力してもらいたい時
  • 重要な情報を表示したい時

これらの場合に、前の画面を操作できないようにしながら、新しい画面やダイアログを表示できます。

https://api.flutter.dev/flutter/widgets/ModalRoute-class.html