Open6

MaterialAppの画面遷移周りのパラメーター

muranakarmuranakar

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

MaterialAppは以下の順序で画面遷移のルートを検索します。

  1. /(初期ルート)の場合:

    • homeプロパティが設定されていればそれを使用
  2. その他のルートの場合:

    • まずroutesテーブルで定義されたルートを検索
    • 見つからない場合はonGenerateRouteを呼び出し
    • それでも見つからない場合はonUnknownRouteを呼び出し

具体的な実装例を2つ紹介します:

  1. シンプルなホーム画面のみの場合:
MaterialApp(
  home: Scaffold(
    appBar: AppBar(
      title: const Text('Home'),
    ),
  ),
)
  1. 複数画面を持つ場合:
MaterialApp(
  routes: <String, WidgetBuilder>{
    '/': (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Home Route'),
        ),
      );
    },
    '/about': (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('About Route'),
        ),
      );
    }
  },
)

画面遷移に関する重要なプロパティ:

  • navigatorKey: Navigatorを制御するためのグローバルキー
  • initialRoute: 初期表示するルート名
  • onGenerateRoute: 動的なルート生成用のコールバック
  • onUnknownRoute: 未定義のルートが要求された場合のフォールバック
  • navigatorObservers: 画面遷移を監視するためのオブザーバーリスト

これらのプロパティを適切に組み合わせることで、アプリケーションの画面遷移を柔軟に制御できます。

以下に詳細を深堀りしていく。

muranakarmuranakar

https://api.flutter.dev/flutter/cupertino/CupertinoApp/navigatorKey.html

navigatorKey

  1. 直接操作の実現
  • BuildContext経由でNavigator.of()を使わなくても、NavigatorStateに直接アクセスできます
  • 例: navigatorKey.currentState?.push(...)のように使えます
  1. 使用例と利点
final navigatorKey = GlobalKey<NavigatorState>();

MaterialApp(
  navigatorKey: navigatorKey,
  // ...
)

// どこからでもNavigatorにアクセス可能
navigatorKey.currentState?.push(...);
  1. 注意点
  • navigatorKeyを変更すると、新しいNavigatorが作成されます
  • その結果、アプリの状態(ナビゲーション履歴など)が失われます
  • navigatorObserversも併せて変更する必要があります
  1. 制約事項
  • onGenerateRouteがnullの場合、navigatorKeyもnullでなければなりません
  • これは、Navigatorが構築されない場合、キーも不要だからです
muranakarmuranakar

https://api.flutter.dev/flutter/cupertino/CupertinoApp/navigatorObservers.html

navigatorObservers

NavigatorObserver は Flutter のナビゲーション(画面遷移)を監視/観察するためのクラスです。

主な用途は:

  1. 画面遷移の監視
  • ページがプッシュされた時
  • ページがポップされた時
  • ルート変更時
    これらの遷移イベントをキャッチできます

簡単な例を示します:

class MyNavigatorObserver extends NavigatorObserver {
  
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    // 新しい画面がプッシュされた時
    print('新しいページへ遷移: ${route.settings.name}');
  }

  
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    // 画面がポップされた時
    print('前のページに戻る: ${previousRoute?.settings.name}');
  }
}

// 使用例:
MaterialApp(
  navigatorObservers: [MyNavigatorObserver()],
  // ...
)

主な使用ケース:

  1. アナリティクス追跡
    • 画面遷移を記録して分析
  2. デバッグ
    • 開発時に画面遷移を追跡
  3. カスタム遷移アニメーション
    • 遷移時の特別な効果の実装

注意点:

  • navigatorKey が変更された場合は、新しいオブザーバーのリストを作り直す必要があります
  • routes が設定されていない場合は、navigatorObservers は空リストである必要があります
muranakarmuranakar

onGenerateInitialRoutes とは?

onGenerateInitialRoutes は、アプリ起動時の最初の画面(ルート)を設定するためのコールバックです。複数の画面を同時に設定できる特徴があり、柔軟な初期画面設定が可能です。

基本的な使い方

MaterialApp(
  initialRoute: '/home',
  onGenerateInitialRoutes: (String initialRoute) {
    return [
      MaterialPageRoute(builder: (context) => HomeScreen()),
      MaterialPageRoute(builder: (context) => WelcomeScreen()),
    ];
  },
)

ユースケース

1. 通常のアプリ起動

MaterialApp(
  initialRoute: '/home',
  onGenerateInitialRoutes: (initialRoute) => [
    MaterialPageRoute(builder: (context) => HomeScreen()),
  ],
)

2. チュートリアル付きの起動

MaterialApp(
  initialRoute: '/tutorial',
  onGenerateInitialRoutes: (initialRoute) => [
    MaterialPageRoute(builder: (context) => HomeScreen()),
    MaterialPageRoute(builder: (context) => TutorialScreen()),
  ],
)

3. ディープリンク対応

MaterialApp(
  initialRoute: '/products/123',
  onGenerateInitialRoutes: (initialRoute) {
    final productId = initialRoute.split('/').last;
    return [
      MaterialPageRoute(builder: (context) => HomeScreen()),
      MaterialPageRoute(builder: (context) => ProductListScreen()),
      MaterialPageRoute(builder: (context) => ProductDetailScreen(id: productId)),
    ];
  },
)

メリット

  • 複数画面の同時設定が可能
  • ディープリンクの実装が簡単
  • 柔軟な初期画面制御

注意点

  • initialRoute が設定されている場合のみ動作
  • アプリ起動時の1回のみ呼び出される
  • 設定しない場合は Navigator.defaultGenerateInitialRoutes が使用される

まとめ

  • 複雑な初期画面遷移が必要な場合
  • ディープリンク対応が必要な場合
  • チュートリアルなど、複数画面のスタックが必要な場合

適切に活用することで、よりユーザーフレンドリーなアプリ開発が可能になります。

muranakarmuranakar

https://api.flutter.dev/flutter/material/MaterialApp/onGenerateRoute.html

onGenerateRouteとは

onGenerateRouteは、名前付きルートが要求されたときに呼び出されるコールバック関数です。routesプロパティで定義されていないルートが要求された場合に使用されます。

基本的な実装例を見てみましょう:

MaterialApp(
  onGenerateRoute: (settings) {
    // ルート名を取得
    final name = settings.name;
    // 渡されたパラメータを取得
    final args = settings.arguments;
    
    // ルートの生成処理
    switch (name) {
      case '/detail':
        return MaterialPageRoute(
          builder: (context) => DetailPage(id: args as String),
        );
      default:
        return null;
    }
  },
)

実践的な使用例

1. パラメータを含むルーティング

商品詳細ページへの遷移を例に考えてみましょう:

// 商品詳細ページ
class ProductDetailPage extends StatelessWidget {
  final String productId;
  
  const ProductDetailPage({required this.productId});
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('商品詳細')),
      body: Text('商品ID: $productId'),
    );
  }
}

// ルーティングの設定
MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name?.startsWith('/product/') ?? false) {
      final productId = settings.name!.split('/').last;
      return MaterialPageRoute(
        builder: (context) => ProductDetailPage(productId: productId),
      );
    }
    return null;
  },
)

2. 遷移アニメーションのカスタマイズ

カスタムトランジションを適用する例:

class FadePageRoute<T> extends PageRoute<T> {
  final Widget child;
  
  FadePageRoute({required this.child});
  
  
  Color get barrierColor => Colors.transparent;
  
  
  String? get barrierLabel => null;
  
  
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    return FadeTransition(
      opacity: animation,
      child: child,
    );
  }
  
  
  bool get maintainState => true;
  
  
  Duration get transitionDuration => Duration(milliseconds: 300);
}

// 使用例
MaterialApp(
  onGenerateRoute: (settings) {
    switch (settings.name) {
      case '/smooth-transition':
        return FadePageRoute(
          child: SmoothTransitionPage(),
        );
    }
    return null;
  },
)

注意点

  1. onGenerateRoutenullを返す場合、アプリケーションはNavigator.defaultRouteName('/')にフォールバックします。

  2. 通常の運用では、onGenerateRoutenullを返すべきではありません。

muranakarmuranakar

https://api.flutter.dev/flutter/material/MaterialApp/onUnknownRoute.html

onUnknownRouteとは

onUnknownRouteは、Flutterアプリケーションで存在しないルートにアクセスしようとした際のフォールバックハンドラーとして機能する重要なプロパティです。

基本構文

MaterialApp(
  onUnknownRoute: (RouteSettings settings) {
    return MaterialPageRoute(
      builder: (BuildContext context) {
        return const NotFoundPage();
      },
    );
  },
);

呼び出されるタイミング

onUnknownRouteは以下の場合に呼び出されます:

  1. onGenerateRouteがルートの生成に失敗した場合
  2. 指定されたルートがroutesマップに存在しない場合

一般的なユースケース

1. エラーログの記録

onUnknownRoute: (RouteSettings settings) {
  // エラーログの記録
  debugPrint('未知のルートへのアクセス: ${settings.name}');
  
  return MaterialPageRoute(
    builder: (context) => const NotFoundPage(),
  );
},

2. アナリティクス連携

onUnknownRoute: (RouteSettings settings) {
  // アナリティクスイベントの送信
  analytics.logEvent(
    name: 'unknown_route_access',
    parameters: {'route': settings.name},
  );
  
  return MaterialPageRoute(
    builder: (context) => const NotFoundPage(),
  );
},

注意点

  1. onUnknownRouteは最後の手段として使用されます
  2. 初期ルート(initialRoute)には適用されません
  3. アプリ内のエラーや外部(Androidインテントなど)からのルートリクエストで発生する可能性があります