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 操作が呼び出されます。本文の内容は以下の通りです:
- 基本的なルートナビゲーション
- ルートパラメータの受け渡し
- その他のルートナビゲーション
基本的なルートナビゲーション#
前述のように、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 を確認できます。