banner
jzman

jzman

Coding、思考、自觉。
github

FlutterシリーズのNavigatorコンポーネントの使用

PS:何かをするのは簡単ですが、実際に何かをするのは難しいです。

Navigator はスタックルールを使用して Widget を管理し、Navigator はページのアクセス履歴を記録します。Navigator を使用してページ間の遷移操作を行うことができます。

Android 開発では、私たちが通常言う「遷移」とは Activity の遷移を指し、ページ遷移とも呼ばれます。Flutter では、これらは Route の遷移を指します。Android のページは Flutter では Route に対応し、Navigator は Route オブジェクトのスタック管理を担当し、Navigator.push や Navigator.pop のようなスタック管理のメソッドを提供します。

上記のように、Flutter は Route の入栈と出栈のメソッドを提供しています。Android の一部のデバイスには戻るキーがあり、この戻るキーは Flutter の Navigator.push および Navigator.pop メソッドと互換性があります。もし特定のデバイスに対応する戻るキーがない場合は、AppBar に戻るボタンを自分で追加できます。Scaffold にはすでに戻るボタンが追加されており、トリガーされると Navigator.pop 操作が呼び出されます。本文の内容は以下の通りです:

  1. 基本的なルートナビゲーション
  2. ルートパラメータの受け渡し
  3. その他のルートナビゲーション

基本的なルートナビゲーション#

前述のように、Flutter ではスタックを使用して Widget を管理し、入栈と出栈のメソッドはそれぞれ Navigator.push と Navigator.pop です。この 2 つのメソッドを使用してページ間の遷移と戻り操作を行います。

Navigator.push#

Navigator.push は Route の入栈操作を実行するために使用され、指定された Route を介して対応するページに遷移できます。メソッドは以下の通りです:

/// パラメータ:(コンテキスト、具体的なルート)
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
    return Navigator.of(context).push(route);
}

MaterialPageRoute を使用して対応するページのルートを構築し、使用方法は以下の通りです:

// NavigatorPushPopPageに遷移
_navigateToPage(context, NavigatorPushPopPage());

/// Navigator.push
/// ページ遷移
_navigateToPage(BuildContext context, Widget widget) {
  Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
    return widget;
  }));
}

Navigator.pop#

Navigator.pop は Route の退栈操作を実行し、ページを戻ります。オプションのパラメータ result を追加して、ページが戻るときに持ち帰るパラメータを指定できます。メソッドは以下の通りです:

/// パラメータ:(コンテキスト、戻るときに持ち帰るパラメータ(オプション))
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
    return Navigator.of(context).pop<T>(result);
}

以下のように、IconButton をクリックして現在のページを退出します:

IconButton(
    icon: Icon(Icons.arrow_back),
    onPressed: () => Navigator.pop(context)),

Navigator.pushNamed#

Navigator.pushNamed は、名前付き Route の入栈操作を実行するために使用され、オプションのパラメータ arguments を介してパラメータを渡すことができます。メソッドは以下の通りです:

/// パラメータ:(コンテキスト、ルート名、持ち運ぶパラメータ(オプション))
static Future<T> pushNamed<T extends Object>(
    BuildContext context,
    String routeName, {
    Object arguments,
   }) {
    return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
}

使用する際は、まず MaterialApp の中で対応するルート名をルート表 routes に追加します。コードは以下の通りです:

class MyApp extends StatelessWidget {
  // このウィジェットはアプリケーションのルートです。
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
      routes: <String, WidgetBuilder>{
        // 対応するルート/NavigatorPushNamedPage
        NavigatorPushNamedPage.routeName: (BuildContext context) =>
            NavigatorPushNamedPage(),
      },
    );
  }
}

/// ページ
/// Navigator.pushNamed
/// 名前付きルートを使用
class NavigatorPushNamedPage extends StatelessWidget {
  static final routeName = '/NavigatorPushNamedPage';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Navigator.pushNamed"),
        centerTitle: true,
      ),
      body: Center(
        child: Text(
          "Navigator.pushNamed",
          style: TextStyle(fontSize: 18),
        ),
      ),
    );
  }
}

これで Navigator.pushNamed を使用して NavigatorPushNamedPage に遷移できます。以下のように:

// NavigatorPushNamedPageに遷移
_navigatePushNamedPage(context, NavigatorPushNamedPage.routeName);

/// Navigator.pushNamed
/// ページ遷移
_navigatePushNamedPage(BuildContext context, String routeName,
    [Object arguments]) {
  Navigator.pushNamed(context, routeName, arguments: arguments);
}

以上が Flutter における最も基本的なページナビゲーションの方法です。Navigator.push でも Navigator.pushNamed でも、NavigatorState の push メソッドに基づいて実装されています。NavigatorState は具体的な BuildContext を介して Navigator.of (context) で取得され、NavigatorState の push メソッドは以下の通りです:

/// NavigatorState.push
Future<T> push<T extends Object>(Route<T> route) {
    assert(!_debugLocked);
    assert(() { _debugLocked = true; return true; }());
    assert(route != null);
    assert(route._navigator == null);
    final Route<dynamic> oldRoute = _history.isNotEmpty ? _history.last : null;
    route._navigator = this;
    route.install(_currentOverlayEntry);
    _history.add(route);
    route.didPush();
    route.didChangeNext(null);
    if (oldRoute != null) {
      oldRoute.didChangeNext(route);
      route.didChangePrevious(oldRoute);
    }
    for (NavigatorObserver observer in widget.observers)
      observer.didPush(route, oldRoute);
    RouteNotificationMessages.maybeNotifyRouteChange(_routePushedMethod, route, oldRoute);
    assert(() { _debugLocked = false; return true; }());
    _afterNavigation(route);
    return route.popped;
}

次に、Flutter におけるパラメータの受け渡しについて説明します。これにはページ遷移時のパラメータの受け渡しとページ戻り時のパラメータの受け渡しが含まれます。

ルートパラメータの受け渡し#

ページ遷移プロセスにおけるパラメータの受け渡しには、ページ遷移時に持ち運ぶパラメータとページ戻り時に持ち運ぶパラメータが含まれます。

Navigator.push でのパラメータの受け渡し#

Navigator.push を使用してパラメータを持ってページ遷移を行う場合、パラメータは対応するページのコンストラクタで受け取ります。具体的な使用例は以下の通りです:

/// NavigatorPushWithParamPageに遷移
_navigateToPage(context,
    NavigatorPushWithParamPage(
      param: "この情報は前のページからのものです!",
    ));

/// Navigator.push/pop
/// ページ遷移
_navigateToPage(BuildContext context, Widget widget) {
  Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
    return widget;
  }));
}

/// ページ
/// Navigator.pushでのパラメータの受け渡し
class NavigatorPushWithParamPage extends StatelessWidget {
  // パラメータ
  final String param;

  NavigatorPushWithParamPage({
    this.param,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Navigator.pushでのパラメータの受け渡し"),
        centerTitle: true,
      ),
      body: Center(
        child: Text(
          "arguments:${this.param}",
          style: TextStyle(fontSize: 18),
        ),
      ),
    );
  }
}

Navigator.pushNamed でのパラメータの受け渡し#

上記のように、Navigator.pushNamed (context, routeName, {arguments}) メソッドのオプションパラメータ arguments は、遷移時に持ち運ぶパラメータです。まず、MaterialApp の onGenerateRoute で arguments を受け取ります。以下のように:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
      // パラメータの受け取り
      onGenerateRoute: (RouteSettings settings) {
        if (settings.name == NavigatorPushNamedWithParamPage.routeName) {
          return MaterialPageRoute<String>(builder: (BuildContext context) {
            return NavigatorPushNamedWithParamPage(settings.arguments);
          });
        } else {
          return null;
        }
      },
    );
  }
}

その後、Navigator.pushNamed を使用してページ遷移を行い、パラメータは対応するページのコンストラクタで受け取ります。以下のように:

/// NavigatorPushNamedWithParamPageに遷移
_navigatePushNamedPage(
    context,
    NavigatorPushNamedWithParamPage.routeName,
    "この情報は前のページからのものです!");
    
/// Navigator.pushNamedでのパラメータの受け渡し
_navigatePushNamedPage(BuildContext context, String routeName,
    [Object arguments]) {
  Navigator.pushNamed(context, routeName, arguments: arguments);
}

/// ページ
/// Navigator.pushNamedでのパラメータの受け渡し
/// 名前付きルートを使用
class NavigatorPushNamedWithParamPage extends StatelessWidget {
  static final String routeName = '/NavigatorPushNamedWithParamPage';
  final String info;

  NavigatorPushNamedWithParamPage(this.info);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Navigator.pushNamedでのパラメータの受け渡し"),
          centerTitle: true,
        ),
        body: Center(
          child: Text(
            "arguments:${this.info}",
            style: TextStyle(fontSize: 18),
          ),
        ),
      ),
    );
  }
}

ページ戻り時のパラメータの受け渡し#

上記のように、Navigator.pop (context, [result]) メソッドのオプションパラメータ result は、ページ戻り時に持ち帰るパラメータです。Navigator.push は Future を返し、then 文でページ戻りの結果を処理します。具体的な使用例は以下の通りです:

/// NavigatorPopWithParamPageに遷移
_navigatePopWithParamPage(context, NavigatorPopWithParamPage());

/// Navigator.popで戻るときにパラメータを持ち帰る
_navigatePopWithParamPage(BuildContext context, Widget widget) {
  Navigator.push<String>(context,
      MaterialPageRoute(builder: (BuildContext context) {
    return widget;
  })).then((result) {
    // 戻るときに持ち帰るパラメータの処理
    Toast.show("Navigator.popで戻るときに持ち帰るパラメータ:" + result, context);
  });
}

/// ページ
/// Navigator.popで戻るときにパラメータを持ち帰る
class NavigatorPopWithParamPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
        child: Scaffold(
          appBar: AppBar(
            title: Text("Navigator.popで戻るときにパラメータを持ち帰る"),
            centerTitle: true,
          ),
          body: Center(
            child: Text(
              "Navigator.popで戻るときにパラメータを持ち帰る",
              style: TextStyle(fontSize: 18),
            ),
          ),
        ),
        onWillPop: () => _popBack(context));
  }

  /// ページを戻り、戻るパラメータを設定します。AndroidのsetResultメソッドに似ています。
  _setResult(BuildContext context) {
    Navigator.pop(context, "これはNavigatorPopWithParamPageからのメッセージです!");
  }

  /// 戻るキーを統一して処理します。
  Future<bool> _popBack(BuildContext context) {
    _setResult(context);
    return Future.value(false);
  }
}

その他のルートナビゲーション#

その他の一般的なルートナビゲーション方法は以下の通りです:

// 現在のルートをNavigatorから削除して新しいルートに遷移します。finishしてstartActivityするのと同じです。
Navigator.popAndPushNamed
// 指定されたRouteに直接戻り、以前のルートはクリアされます。
Navigator.popUntil
// 新しいRouteに遷移し、指定されたRoute以前のRouteをクリアします。pushNamedAndRemoveUntilと似ています。
Navigator.pushAndRemoveUntil
// ページを置き換えます。pushReplacementと似ています。
Navigator.pushReplacement

その他のルートに関連する操作メソッドは一つ一つ挙げませんが、関連 API を確認できます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。