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'),
),
),
);
}
}

