Navigator.push
需要指定 Route
實例,若要切換的頁面變多時,會造成 Route
的指定,分散在程式碼的多個位置,這時可以使用具名路由(Named routes),為每個路由命名、集中管理。
來直接看看〈Navigator 與 MaterialPageRoute〉中的第一個範例,如何改用具名路由:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
title: 'Openhome',
// 設定初始路由,initialRoute 預設值其實就是 '/'
initialRoute: '/',
// 路由表
routes: {
'/' : (_) => MainPage(),
'/detail' : (_) => DetailPage()
}
));
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主畫面'),
),
body: GestureDetector(
onTap: () {
// 使用 pushNamed 指定路由名稱
Navigator.pushNamed(context, '/detail');
},
child: Image.asset('images/caterpillar.png'),
),
);
}
}
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () => Navigator.pop(context),
child: Center(
child: Image.asset('images/caterpillar.png'),
),
),
);
}
}
MaterialApp
可以設定 routes
,路由表是藉由 Map<String, Widget Function(BuildContext)>
來指定,initialRoute
可以指定初始時要顯示的路由,若想指定某個路由置入 Navigator
的堆疊,可以使用 Navigator.pushNamed
指定路由名稱。
問題來了,若路由表集中在 routes
指定了,該怎麼在操作時,傳遞特定資料給頁面呢?Navigator.pushNamed
可以指定 arguments
,在後續建構 Widget
的相關場合中,若可以取得 BuildContext
,就可以透過 ModalRoute.of(context).settings.arguments
,來取得各路由被置入堆疊時指定的 arguments
。
例如,若要將〈Navigator 與 MaterialPageRoute〉中第一個範例,改為使用具名路由的話,可以如下:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
title: 'Openhome',
routes: {
'/' : (_) => MainPage(),
// 取得 pushNamed 傳入的 arguments
'/detail' : (context) => DetailPage(ModalRoute.of(context).settings.arguments)
}
));
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主畫面'),
),
body: GestureDetector(
// 指定的 arguments
onTap: () => Navigator.pushNamed(context, '/detail', arguments: '說明'),
child: Image.asset('images/caterpillar.png'),
),
);
}
}
class DetailPage extends StatelessWidget {
String title;
DetailPage(this.title);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: GestureDetector(
onTap: () => Navigator.pop(context, '結果值'),
child: Center(
child: Image.asset('images/caterpillar.png'),
),
),
);
}
}
為了不修改 DetailPage
,在建立 DetailPage
實例時,透過 ModalRoute.of(context).settings.arguments
取得了 Navigator.pushNamed
指定的 arguments
;你也可以修改一下 DetailPage
,不透過建構式傳入 title
:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
title: 'Openhome',
routes: {
'/' : (_) => MainPage(),
'/detail' : (_) => DetailPage()
}
));
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主畫面'),
),
body: GestureDetector(
onTap: () => Navigator.pushNamed(context, '/detail', arguments: '說明'),
child: Image.asset('images/caterpillar.png'),
),
);
}
}
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// 透過 ModalRoute.of(context).settings.arguments 取得 title
title: Text(ModalRoute.of(context).settings.arguments),
),
body: GestureDetector(
onTap: () => Navigator.pop(context, '結果值'),
child: Center(
child: Image.asset('images/caterpillar.png'),
),
),
);
}
}