本文中涉及部分非Flutter的stable
版本(2019年2月25日 為止)
,您可查閱Flutter相關文件檢視新功能是否同步的stable
分支或者切換其他分支(如master
)中體驗
引言
在我們使用Flutter開發App時,路由是必須用到的。
Flutter提供了兩種方式進行路由,分別是 Navigator.push()
(例) 以及 Navigator.pushNamed()
(例)。
對於這兩種方式各有各的優點與缺點:
- Navigator.push()
- 優點:動態、自由度大,可以以不同的動畫方式跳轉到新頁面,且可以傳遞引數到新的頁面。
- 缺點:會造成程式碼冗餘,而且不便於程式碼維護。(當然你可以將其進行封裝 這裡不討論這一點)
- Navigator.pushNamed()
- 優點:一句話就能實現頁面的跳轉與目前大多數框架的方式相似。
- 缺點:不能傳遞引數!不能傳遞引數!不能傳遞引數!
選擇
在實際開發運用中,我們也是更加傾向於Named
路由方式。
但是唯一不足之處就是它不支援傳遞引數,這一點實在是令人抓狂。
其實在Flutter的Issues中16年就有人提出這個問題,但是這個Issue一直到今年才有PR被提交(目前為止這個功能僅僅被合併進master分支並沒有同步到bate或者stable)
上手體驗
- 首先我們要切到master分支下
執行
flutter channel master
然後再執行命令flutter upgrade
保證你處於最新的版本。即可切換到master分支下
- 建立一個Flutter專案
- 這裡我們在
main.dart
中略作修改
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: GestureDetector(
onTap: (){
// TODO
},
child: Text("go next page with params"),
),
),
);
}
}
複製程式碼
- 新增第二個頁面
page.dart
import 'package:flutter/material.dart';
class Page extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Text("hi this is next page"),
),
);
}
}
複製程式碼
- 新增路由並跳轉同時傳遞引數
main.dart
import 'package:flutter/material.dart';
// 引入新頁面
import 'page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
// 處理Named頁面跳轉 傳遞引數
onGenerateRoute: (RouteSettings setting) {
if(setting.name == '/page') {
return MaterialPageRoute(builder: (context) => Page(id: setting.arguments['id']));
}
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: GestureDetector(
onTap: (){
// 進行Named頁面跳轉 傳遞引數
Navigator.pushNamed(context, '/page', arguments: { "id": 1} );
},
child: Text("go next page with params"),
),
),
);
}
}
複製程式碼
- 頁面接受引數
page.dart
import 'package:flutter/material.dart';
class Page extends StatelessWidget{
Page({this.id});
final int id;
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Text("hi this is next page, id is $id"),
),
);
}
}
複製程式碼
效果
優化
這裡我們還是要在onGenerateRoute
處理我們的Named跳轉,我們在對他進行優化一下。
(目前沒辦法在MaterialApp的routes進行處理,原因可見原始碼(一)(二))
原始碼一處:呼叫
widget.pageRouteBuilder
並傳入settings
(arguments
在settings
中)原始碼二處:
pageRouteBuilder
被寫死為構建一個MaterialPageRoute
,而MaterialPageRoute
中並沒有對settings
進行傳遞所以我們只能自己在
onGenerateRoute
中進行處理。(希望官網也能繼續優化,emmmm拭目以待)
/**
* main.dart
*/
import 'package:flutter/material.dart';
// 引入新頁面
import 'page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 定義路由資訊
final Map<String, Function> routes = {
'/page': (context, {arguments}) => Page(arguments: arguments)
};
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
// 處理Named頁面跳轉 傳遞引數
onGenerateRoute: (RouteSettings settings) {
// 統一處理
final String name = settings.name;
final Function pageContentBuilder = this.routes[name];
if (pageContentBuilder != null) {
final Route route = MaterialPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
}
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Center(
child: GestureDetector(
onTap: () {
// 進行Named頁面跳轉 傳遞引數
Navigator.pushNamed(context, '/page', arguments: {'id': 123});
},
child: Text("go next page with params"),
),
),
);
}
}
/**
* page.dart
*/
import 'package:flutter/material.dart';
class Page extends StatelessWidget{
Page({this.arguments});
final Map arguments;
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Text("hi this is next page, id is ${arguments != null ? arguments['id'] : '0'}"),
),
);
}
}
複製程式碼