Flutter路由介紹
跟Web頁或者原生APP一樣,我們在使用Flutter 開發APP時也會涉及到多頁面之間的跳轉、參數傳遞、參數回傳等業務,
Flutter路由
能滿足上述我們提到的所有業務類型,此外我們也可以結合Flutter動畫
給路由跳頁時添加個性化的跳頁動畫操作,我會在后續Flutter動畫
章節中具體講解。通過本節專題,讀者不僅僅可以自己動手做一些簡單的UI,還能利用Fluttter 路由
結合之前的課程分享做一些簡單的多頁面Flutter App。
本期課程目標
- 了解并掌握Flutter路由的簡單使用
- 掌握Flutter動態路由跟靜態路由的區別
- 掌握Flutter路由在頁面間的參數傳遞以及回傳流程
- 借助路由結合之前的課程做一些簡單的多頁面Flutter APP
關于靜態路由跟動態路由
在Flutter中路由分為靜態路由
跟動態路由
兩種:Flutter中所謂的靜態路由指的是需要提前把各個需要跳轉的頁面路徑注冊在routes: <String, WidgetBuilder> {}
中,且靜態路由不支持向下一個頁面傳遞參數,但是可以接收下一個頁面的返回值
。
動態路由使用就相對來說比較靈活一點,動態路由同樣支持向下一個頁面傳遞參數,而且在使用時不需要我們提前規劃好頁面路徑,只需要在具體跳頁邏輯中自己去構造MaterialPageRoute
對象來完成頁面跳轉,或者用PageRouterBuilder
來自定義路由跳轉時的動畫,關于路由跳轉動畫
我會在Flutter動畫章節中具體講解,當然動態路由同樣也支持頁面參數回傳。
路由場景分類
1.靜態路由跳頁
場景一:點擊A頁面中的按鈕跳轉到B頁,不涉及到數據傳遞以及回傳
效果圖
靜態路由使用時要求我們在
MaterialApp
中的routes中提前注冊路由
new MaterialApp(
home: new FlutterDemo(),
routes: <String, WidgetBuilder>{
'router/new_page': (_) => new StaticNavigatorPage()
}));
A頁面代碼:
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/StaticNavigatorPage.dart';
void main() {
runApp(new MaterialApp(
home: new FlutterDemo(),
routes: <String, WidgetBuilder>{
'router/new_page': (_) => new StaticNavigatorPage()
}));
}
class FlutterDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Flutter進階之旅"),
),
body: new Center(
child: new RaisedButton(
child: new Text("靜態路由跳頁"),
onPressed: () {
Navigator.of(context)
.pushNamed('router/new_page'); //這里一定要保證跳頁的路由路徑跟上面注冊的路徑一致
})),
);
}
}
B頁面代碼:
import 'package:flutter/material.dart';
class StaticNavigatorPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("靜態路由頁"),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("返回"),
),
body: new Center(
child: Text("靜態路由可以傳入一個routes參數來定義路由。但是這里定義的路由是靜態的,"
"它不可以向下一個頁面傳遞參數,利用push到一個新頁面,pushNamed方法是有一個Future的返回值的"
",所以靜態路由也是可以接收下一個頁面的返回值的。但是不能向下一個頁面傳遞參數"),
),
);
}
}
上述借助路由跳頁過程中我們注意到,大概分以下幾步:
1.注冊路由且保證路由的唯一性
2.跳頁時使用Navigator.of(context).pushNamed('路由地址');
3.使用Navigator.of(context).pop();
結束當前頁
2.靜態路由跳頁接收下一頁的返回值
場景二:點擊A頁面上的按鈕跳頁到B頁面,在B頁面銷毀后A頁面接收到B頁面回傳回來的值并且顯示在
AlertDialog
上
效果圖
A頁面代碼:
使用Navigator push一個新頁面,pushNamed方法是有一個Future的返回值的,在then回調中監聽并接收新頁面回傳回來的數據,并且借助
showDialog
顯示在Dialog
上
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/StaticNavigatorPageWithParams.dart';
void main() {
runApp(
new MaterialApp(home: new FlutterDemo(), routes: <String, WidgetBuilder>{
'router/new_page_with_callback': (_) => new StaticNavigatorPageWithResult()
}));
}
class FlutterDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Flutter進階之旅"),
),
body: new Center(
child: new RaisedButton(
child: new Text("靜態路由接收下一頁返回值"),
onPressed: () {
Navigator.of(context)
.pushNamed('router/new_page_with_callback')
.then((value) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(value),
));
});
})),
);
}
}
B頁面代碼:
從效果圖中可以看到,當我點擊B頁面中間的按鈕時會把數據回傳給上一頁,但是直接點擊導航欄左上角的返回按鈕回到A頁面時并不會把數據傳遞給上一個頁面,這里是因為我在B頁面的按鈕上pop頁面出棧的時候把參數放進里面作為了參數傳遞,pop()
可接收一個Object對象作為參數傳遞
Navigator.of(context).pop(T extends Object);
這就告訴我們當我們需要給上一個頁面回傳數據的時候可直接借助pop傳遞Navigator.of(context).pop("頁面結束后返回的數據");
,不需要傳值的時候直接返回空對象Navigator.of(context).pop()
即可。
import 'package:flutter/material.dart';
class StaticNavigatorPageWithResult extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("靜態路由帶返回參數"),
),
body: new Center(
child: new OutlineButton(
onPressed: () {
Navigator.of(context).pop("頁面結束后返回的數據");
},
child: Text("點我返回上個頁面結束后返回的數據"),
),
),
);
}
}
3.動態路由跳頁
文章的開頭我們提到借助動態路由可以向下一個頁面傳遞參數,同樣也可以接收新頁面回傳回來的數據。下面我模擬兩個使用動態路由的場景,既然動態路由可以傳值那就肯定可以不傳值跳頁,我就不模擬動態路由不傳值跳頁的例子了,讀者借助靜態路由的樣例自行測試即可,我們主要講解一下借助動態路由傳值的例子。
場景三:點擊A頁面中的按鈕,把用戶名跟密碼傳遞給下一個頁面B頁面,B頁面處理完接收到的數據后把結果回傳給A頁面,A頁面中把從B頁面回傳回來的數據顯示在Dialog上。
模擬效果圖
使用動態路由時我們不再需要像靜態路由那樣在
MaterialApp
中的router中提前注冊路由路徑,只需要在使用Navigator.push
傳入MaterialPageRoute對象即可
Navigator.push(
context,
new MaterialPageRoute(
//_代表參數為空
builder: (_) => new DynamicNaviattionPage(
username: "xiedong",
password: "123456",
)));
A頁面代碼:
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/simpleWidget/navigator/DynamicNavigationPage.dart';
void main() {
runApp(new MaterialApp(home: new FlutterDemo()));
}
class FlutterDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Flutter進階之旅"),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
//_代表參數為空
builder: (_) => new DynamicNaviattionPage(
username: "xiedong",
password: "123456",
))).then((value) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(value),
));
});
},
child: new Text("動態路由傳參"),
)));
}
}
B頁面代碼:
import 'package:flutter/material.dart';
class DynamicNaviattionPage extends StatelessWidget {
var username;
var password;
DynamicNaviattionPage({Key key, this.username, this.password})
: super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("動態路由"),
),
body: new Center(
child: new Column(
children: <Widget>[
new MaterialButton(
onPressed: () {
Navigator.pop(context, "未查詢到改該用戶信息");
},
child: new Text("點我返回"),
color: Colors.lightGreen,
),
new Text("上頁傳遞過來的username $username"),
new Text("上頁傳遞過來的password $password"),
],
),
),
);
}
}
關于路由重點總結
- Flutter路由分為靜態路由跟動態路由,靜態路由不支持向下一個頁面傳遞參數,動態路由可傳遞
- 靜態路由使用時需要提前注冊聲明頁面路徑,
- 動態路由可以直接在使用時構造路由對象,不需要提前注冊路徑。
- 兩種類型都支持接收下一頁面回傳回來的值