RouteはFlutterの抽象クラスで、Navigatorのナビゲーション履歴内の個別の画面やページを表します。Routeの具体的な実装であるMaterialPageRoute、CupertinoPageRoute、PlatformRouteは、画面の表示方法と遷移時に使用するアニメーションを決定します。通常のウィジェットとは異なり、RouteにはdidPush、didPop、didReplace、didChangeNextというメソッドを持つ独自のライフサイクルがあります。Flutter API Reference (2026)によると、各RouteはModalBarrierを管理し、プラットフォーム固有の機能(iOSのスワイプバック)を考慮し、画面間の状態の分離を保証します。
重要ポイント
RouteはFlutterのナビゲーションシステムの基盤です。ユーザーがアプリケーションで見る各画面は、Navigatorスタック内にあるRouteオブジェクトで表されます。Routeは制御コードから画面を抽象化します。NavigatorがRouteを追加・削除する一方、Routeの内部にはユーザーが見るインターフェースがあります。このアーキテクチャにより、ナビゲーションと表示の責任が分離されます。
単純なウィジェットの置き換えとは異なり、Routeは通常のウィジェットでは利用できないサービスを提供します:ModalBarrier(ダイアログ表示時の背景の暗転)、出入りのアニメーション制御、Androidのハードウェア戻るボタンの処理、画面間のスムーズな遷移のためのHeroアニメーションとの統合。
Flutter Cookbook (2026)によると、RouteはHeroアニメーションの重要な要素です。あるRouteのHeroウィジェットは、次のRouteのHeroウィジェットへの遷移を自動的にアニメーション化し、要素が“飛ぶ”ような効果を生み出します。これは、Routeがアニメーション中に両方の画面をOverlayに保持するから可能です。
Routeは、シンプルなモバイルアプリケーション(Navigator 1.0経由)と、ディープリンクを伴う複雑なシナリオ(Navigator 2.0)の両方の基盤です。Navigator 2.0では、RouteはRouterDelegateがルート設定から変換するPageを表します。したがって、選択したアプローチやパッケージに関係なく、Flutterのナビゲーションシステムで作業するにはRouteの理解が不可欠です。
Flutterは、それぞれ特定のプラットフォームに動作を適応させた、いくつかの組み込みRoute実装を提供します。正しいRouteタイプを選択することはユーザーエクスペリエンスに影響します。AndroidでのMaterialアニメーションとiOSでのCupertinoアニメーションは、“ネイティブ”アプリケーションの感覚を生み出します。
| Routeの種類 | アニメーション | プラットフォーム | 特徴 |
|---|---|---|---|
| MaterialPageRoute | 下から上にスライド | Android、デスクトップ | 遷移時の影、自動SafeArea処理 |
| CupertinoPageRoute | 右から左にスライド | iOS、iPadOS | ジェスチャースワイプバック、遷移時の透明な背景 |
| PlatformRoute | 自動選択 | 全プラットフォーム | TargetPlatformに基づいてタイプを選択 |
| PageRouteBuilder | カスタム | 全プラットフォーム | AnimationControllerによるアニメーションの完全制御 |
MaterialPageRouteは最もよく使われるRoute実装です。新しい画面が下から上に徐々に現れるようにアニメーションします。終了時には、画面は上から下にアニメーションして元の位置に戻ります。ツールバー(AppBar)と画面本体は別々にアニメーションし、階層効果を生み出します。
CupertinoPageRouteはiOSのUINavigationControllerを模倣します。新しい画面は右から入り、前の画面を覆います。主な特徴は、CupertinoBackGestureDetectorを介して実装されたインタラクティブなスワイプバックジェスチャーのサポートです。このジェスチャーはアニメーション中でも処理され、iPhoneユーザーにはおなじみの自然な動作を提供します。
Routeには、通常のStatefulWidgetのライフサイクルとは異なる独自のライフサイクルがあります。このサイクルを理解することは、適切なデータ初期化、ストリームサブスクリプション、画面終了時のリソース解放に必要です。
Routeのライフサイクルは4つの主要な段階で構成されます。遷移 — Routeが作成され、入場時にアニメーションします(didPushが呼ばれます)。アクティブ — Routeが完全に表示され、ユーザーと対話します。非アクティブ — 別のRouteが現在のRouteを覆います(ダイアログ、ボトムシート)が、Routeはスタックに残ります。破棄 — Routeがスタックから削除され破棄されます。didPopとdisposeが呼ばれます。
Routeのライフサイクルメソッドはカスタム実装でオーバーライドできます。たとえば、didPopはRouteがスタックから削除されるときに呼ばれます。ここで下書きデータを保存できます。didChangeNextはスタック内の次のRouteが変更されたときに呼ばれます。ナビゲーション履歴が変更されたときにUIを更新するのに便利です。
Flutter API Route.didPop (2026)によると、RouteのライフサイクルとRoute内のStateのライフサイクルを混同しないことが重要です。Route内のStatefulWidgetには独自のinitStateとdisposeがあり、これらはそれぞれ遷移段階と破棄段階で呼び出されます。Routeは内部のStateよりも長く生存します。Routeは、そのウィジェットが別のRouteによって一時的に隠されている場合でも、Overlayに残ります。
Routeは、入力時(作成時)と出力時(完了時)の両方でデータを受け渡すメカニズムを提供します。Routeを介した適切なデータ受け渡しにより、グローバル変数やInheritedWidgetが不要になり、ナビゲーションが型安全で予測可能になります。
新しい画面にデータを渡すには、受け取り側ウィジェットのコンストラクターまたはNavigator.pushNamedのargumentsパラメーターを使用します。Route内では、RouteSettings.argumentsを介してデータにアクセスできます。これはRouteオブジェクトに格納されます。このアプローチは、MaterialPageRoute、CupertinoPageRoute、カスタム実装など、すべてのRouteタイプで機能します。
データを返すには、Navigator.pop(context, result)の第2引数を使用します。Navigator.pushはFuture
MaterialPageRouteを使ってNavigator.pushを直接呼び出す場合、データはターゲット画面のコンストラクターを介して渡されます。MethodChannelは使用されません。これは純粋なDartの相互作用です。このアプローチは、複雑なオブジェクトの型安全な受け渡しに適しています。
独自のアニメーションとデータ受け渡しを備えたカスタムRouteを作成する例を見てみましょう。PageRouteBuilderを使用すると、アニメーションのカーブと期間を完全に制御して、入退場アニメーションを定義できます。
// スライドアニメーション付きカスタムRoute
Navigator.push(context, PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return DetailPage(productId: '42');
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 0.3);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition(position: offsetAnimation, child: child);
},
transitionDuration: const Duration(milliseconds: 400),
));
// 画面からデータを返す
ElevatedButton(
onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
child: const Text('選択'),
);
// 呼び出し元画面で結果を取得
final result = await Navigator.push(context, MaterialPageRoute(
builder: (context) => const SelectionPage(),
));
if (result != null) {
print('選択済み: ${result['selected']}');
}
この例では、PageRouteBuilderが透明度を伴う下からのカスタムスライドアニメーションを定義しています。transitionDurationがアニメーションの速度を設定します。コードは結果の受け渡しも示しています。詳細画面はユーザーの選択を含むMapを返し、呼び出し元画面はpushからのFutureを介してこのデータを受け取ります。Routeは完全な分離を保証します。詳細画面の下書きはリストの状態に影響しません。
よくある質問
Routeはナビゲーションレベルで画面を管理するオブジェクトです。アニメーション、ModalBarrier、ライフサイクルを保存します。Widgetはインターフェースの一部の記述です。Routeは内部にWidgetを含みますが、通常のウィジェットでは利用できないサービス(Overlayレイヤー、Heroアニメーション)も提供します。1つのRouteは、任意の深さの複雑なウィジェット階層を含むことができます。
pageBuilder(画面構築)とtransitionsBuilder(アニメーション定義)パラメーターを持つPageRouteBuilderを使用します。transitionsBuilderでは、並列アニメーション用にanimation(0.0–1.0)とsecondaryAnimationが利用可能です。完全に制御するには、Routeのサブクラスを作成し、buildPage、createAnimationController、buildTransitionsをオーバーライドして、低レベルのAnimationControllerにアクセスします。
複雑なオブジェクトを渡すには、Navigator.pushを直接呼び出すときにターゲット画面のコンストラクターを使用するか、pushNamedでargumentsパラメーターを使用します。オブジェクトがシリアル化可能(Map、JSON、またはカスタムクラス)であることを確認してください。Flutterで型安全に受け渡しを行うには、freezedやjson_serializableモデルを使用します。これらはRouteSettingsを介した受け渡し時に正しいデシリアライゼーションを保証します。
RouteがNavigatorスタックに残っている場合、Route.disposeは呼び出されません。たとえば、新しいRouteを開くとき、古いRouteは非アクティブ状態になりますが破棄されません。素早く戻るためにスタックに残ります。Disposeは、pop、pushReplacement、またはpushAndRemoveUntilを介してRouteがスタックから削除された場合にのみ呼び出されます。リソースを解放するには、Route自身のdisposeではなく、Route内のStateのdisposeを使用してください。
BuildContextから現在のRouteを取得するにはModalRoute.of(context)を使用します。ModalRoute.isActiveプロパティは、Routeが現在表示されている画面かどうかを示します。ModalRoute.isCurrent — Routeがスタックの先頭にある場合はtrue。スタックの変更を監視するには、RouteAwareとRouteObserverを介してNavigatorオブザーバーに購読します。これらはアクティブなRouteの変更を通知します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。