Flutterでの基本的な画面遷移の方法(Navigator 1.0)と、画面遷移時に値を受け渡す方法について解説します。
画面遷移の基本「Navigator」
NavigatorはFlutterの画面遷移用ウィジェットです。
画面遷移はpushで、遷移先のウィジェットを指定する方法と、名前で指定する方法の2種類があります。
- Navigator.of(context).push()
- Navigator.of(context).pushNamed()
画面遷移から戻るのはpopです。
- Navigator.pop()
ウィジェットを指定して画面遷移
MaterialPageRouteのbuilderで遷移先のウィジェットを指定して画面遷移します。
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => NextPage(title: 'Next Page'),
),
);
名前をつけて画面遷移
名前付きで画面遷移する場合は、名前付きのルートを設定します。(デフォルトのカウンターアプリのコードで説明)
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// ホームは使わないのでコメントアウト
// home: const MyHomePage(title: 'Flutter Demo'),
// ここでページのルートを設定 --->
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) =>
const MyHomePage(title: 'Home Page'),
'/next': (BuildContext context) =>
const NextPage(title: 'Next Page'),
},// <--- ここまで
);
}
}
initialRoute:はデフォルトで表示されるページなので、一番最初に表示させるページを指定しておきます。そして、routes:に名前付きページを設定します。
画面遷移は、上で設定したルート名を指定します。
Navigator.of(context).pushNamed('/next');
遷移先から戻る
画面遷移先から戻る場合はpop()を使います。
Navigator.pop(context);
これで遷移元の画面に戻ります。
値の受け渡し
値の受け渡しは、Navigatorのargumentsプロパティを使用します。
- Navigator.of(context).push()の場合
// 例としてargumentsにカウンターの値を設定しています
RouteSettings settings = RouteSettings(arguments: _counter);
// 戻り値を受ける場合はawaitで呼び出す(戻り値が無ければ不要)
var result = await Navigator.of(context).push(
MaterialPageRoute(
settings: settings,
builder: (context) => NextPage(title: 'Next'),
),
);
- Navigator.of(context).pushNamed()の場合
// 例としてargumentsにカウンターの値を設定しています
var args = _counter;
// 戻り値を受ける場合はawaitで呼び出す(戻り値が無ければ不要)
var result = await Navigator.of(context)
.pushNamed('/next', arguments: args);
遷移先での値の受け取り
遷移先でargumentsの値を受け取るにはcontextが必要なので、遷移先ウィジェットのbuild以降で次のコードを呼び出します。
Object? args = ModalRoute.of(context)!.settings.arguments;
argumentsはObject型なので、String、int、カスタムクラスなど任意のObjectを受け渡し可能です。使用する際は、as intなどで型を指定してください。
遷移先からの戻り値
popの二番目の引数がresult値なので、ここに遷移元に引き渡す値を指定できます。
Navigator.pop(context, _counter);
※遷移元でこの戻り値を受け取る場合は、先の呼び出しの例に記載した通り、awaitでNavigator.push()/pushNamed()を呼び出してください。
サンプルコード
画面遷移のサンプルコードです。画面遷移元と遷移先の2つのカウンターページで相互にカウント値の受け渡しをしています。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
//homeは使わないのでコメントアウト
//home: const MyHomePage(title: 'Flutter Demo Home Page'),
// ここでページのルートを設定 --->
// ※ページのルート名は各ページのクラスにstatic routeName='hoge'で設定しています
initialRoute: MyHomePage.routeName,
routes: <String, WidgetBuilder>{
MyHomePage.routeName: (BuildContext context) =>
const MyHomePage(title: 'Home Page'),
NextPage.routeName: (BuildContext context) =>
const NextPage(title: 'Next Page'),
}, // <--- ここまで
);
}
}
class MyHomePage extends StatefulWidget {
static const routeName = '/';
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
// 画面遷移ボタン ---
ElevatedButton(
onPressed: () async {
RouteSettings settings = RouteSettings(arguments: _counter);
var result = await Navigator.of(context).push(
MaterialPageRoute(
settings: settings,
builder: (context) => NextPage(title: 'Next'),
),
);
setState(() {
_counter = result as int;
});
},
child: const Text('Next Page'),
),
Divider(),
ElevatedButton(
onPressed: () async {
var args = _counter;
var result = await Navigator.of(context)
.pushNamed('/next', arguments: args);
setState(() {
_counter = result as int;
});
},
child: const Text('Next Page (Named)'),
),
// --- ここまで
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
// Nextページ
class NextPage extends StatefulWidget {
static const routeName = '/next';
const NextPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<NextPage> createState() => _NextPageState();
}
class _NextPageState extends State<NextPage> {
int _counter = 0;
Object? args; //argsの受け取り用
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
// argumentsを受け取る --->
// ※setStateの度にbuildが呼ばれるので初回(asrgがnull)の時だけ受け取る
if (args == null) {
args = ModalRoute.of(context)!.settings.arguments;
_counter = args as int; //Object型なので型を指定する
}
// <--- ここまで
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
// 画面遷移ボタン --->
ElevatedButton(
onPressed: () {
Navigator.pop(context, _counter);
},
child: const Text(
'Home Page',
),
),
// <--- ここまで
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
コメント