Flutter路由介紹
跟Web頁或者原生APP一樣,我們?cè)谑褂肍lutter 開發(fā)APP時(shí)也會(huì)涉及到多頁面之間的跳轉(zhuǎn)、參數(shù)傳遞、參數(shù)回傳等業(yè)務(wù),
Flutter路由能滿足上述我們提到的所有業(yè)務(wù)類型,此外我們也可以結(jié)合Flutter動(dòng)畫給路由跳頁時(shí)添加個(gè)性化的跳頁動(dòng)畫操作,我會(huì)在后續(xù)Flutter動(dòng)畫章節(jié)中具體講解。通過本節(jié)專題,讀者不僅僅可以自己動(dòng)手做一些簡單的UI,還能利用Fluttter 路由結(jié)合之前的課程分享做一些簡單的多頁面Flutter App。
本期課程目標(biāo)
- 了解并掌握Flutter路由的簡單使用
- 掌握Flutter動(dòng)態(tài)路由跟靜態(tài)路由的區(qū)別
- 掌握Flutter路由在頁面間的參數(shù)傳遞以及回傳流程
- 借助路由結(jié)合之前的課程做一些簡單的多頁面Flutter APP
關(guān)于靜態(tài)路由跟動(dòng)態(tài)路由
在Flutter中路由分為靜態(tài)路由跟動(dòng)態(tài)路由兩種:Flutter中所謂的靜態(tài)路由指的是需要提前把各個(gè)需要跳轉(zhuǎn)的頁面路徑注冊(cè)在routes: <String, WidgetBuilder> {}中,且靜態(tài)路由不支持向下一個(gè)頁面?zhèn)鬟f參數(shù),但是可以接收下一個(gè)頁面的返回值。
動(dòng)態(tài)路由使用就相對(duì)來說比較靈活一點(diǎn),動(dòng)態(tài)路由同樣支持向下一個(gè)頁面?zhèn)鬟f參數(shù),而且在使用時(shí)不需要我們提前規(guī)劃好頁面路徑,只需要在具體跳頁邏輯中自己去構(gòu)造MaterialPageRoute對(duì)象來完成頁面跳轉(zhuǎn),或者用PageRouterBuilder來自定義路由跳轉(zhuǎn)時(shí)的動(dòng)畫,關(guān)于路由跳轉(zhuǎn)動(dòng)畫我會(huì)在Flutter動(dòng)畫章節(jié)中具體講解,當(dāng)然動(dòng)態(tài)路由同樣也支持頁面參數(shù)回傳。
路由場景分類
1.靜態(tài)路由跳頁
場景一:點(diǎn)擊A頁面中的按鈕跳轉(zhuǎn)到B頁,不涉及到數(shù)據(jù)傳遞以及回傳
效果圖

靜態(tài)路由使用時(shí)要求我們?cè)?code>MaterialApp中的routes中提前注冊(cè)路由
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進(jìn)階之旅"),
),
body: new Center(
child: new RaisedButton(
child: new Text("靜態(tài)路由跳頁"),
onPressed: () {
Navigator.of(context)
.pushNamed('router/new_page'); //這里一定要保證跳頁的路由路徑跟上面注冊(cè)的路徑一致
})),
);
}
}
B頁面代碼:
import 'package:flutter/material.dart';
class StaticNavigatorPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("靜態(tài)路由頁"),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("返回"),
),
body: new Center(
child: Text("靜態(tài)路由可以傳入一個(gè)routes參數(shù)來定義路由。但是這里定義的路由是靜態(tài)的,"
"它不可以向下一個(gè)頁面?zhèn)鬟f參數(shù),利用push到一個(gè)新頁面,pushNamed方法是有一個(gè)Future的返回值的"
",所以靜態(tài)路由也是可以接收下一個(gè)頁面的返回值的。但是不能向下一個(gè)頁面?zhèn)鬟f參數(shù)"),
),
);
}
}
上述借助路由跳頁過程中我們注意到,大概分以下幾步:
1.注冊(cè)路由且保證路由的唯一性
2.跳頁時(shí)使用Navigator.of(context).pushNamed('路由地址');
3.使用Navigator.of(context).pop();結(jié)束當(dāng)前頁
2.靜態(tài)路由跳頁接收下一頁的返回值
場景二:點(diǎn)擊A頁面上的按鈕跳頁到B頁面,在B頁面銷毀后A頁面接收到B頁面回傳回來的值并且顯示在
AlertDialog上
效果圖

A頁面代碼:
使用Navigator push一個(gè)新頁面,pushNamed方法是有一個(gè)Future的返回值的,在then回調(diào)中監(jiān)聽并接收新頁面回傳回來的數(shù)據(jù),并且借助
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進(jìn)階之旅"),
),
body: new Center(
child: new RaisedButton(
child: new Text("靜態(tài)路由接收下一頁返回值"),
onPressed: () {
Navigator.of(context)
.pushNamed('router/new_page_with_callback')
.then((value) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(value),
));
});
})),
);
}
}
B頁面代碼:
從效果圖中可以看到,當(dāng)我點(diǎn)擊B頁面中間的按鈕時(shí)會(huì)把數(shù)據(jù)回傳給上一頁,但是直接點(diǎn)擊導(dǎo)航欄左上角的返回按鈕回到A頁面時(shí)并不會(huì)把數(shù)據(jù)傳遞給上一個(gè)頁面,這里是因?yàn)槲以贐頁面的按鈕上pop頁面出棧的時(shí)候把參數(shù)放進(jìn)里面作為了參數(shù)傳遞,pop()可接收一個(gè)Object對(duì)象作為參數(shù)傳遞
Navigator.of(context).pop(T extends Object);
這就告訴我們當(dāng)我們需要給上一個(gè)頁面回傳數(shù)據(jù)的時(shí)候可直接借助pop傳遞Navigator.of(context).pop("頁面結(jié)束后返回的數(shù)據(jù)");,不需要傳值的時(shí)候直接返回空對(duì)象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("靜態(tài)路由帶返回參數(shù)"),
),
body: new Center(
child: new OutlineButton(
onPressed: () {
Navigator.of(context).pop("頁面結(jié)束后返回的數(shù)據(jù)");
},
child: Text("點(diǎn)我返回上個(gè)頁面結(jié)束后返回的數(shù)據(jù)"),
),
),
);
}
}
3.動(dòng)態(tài)路由跳頁
文章的開頭我們提到借助動(dòng)態(tài)路由可以向下一個(gè)頁面?zhèn)鬟f參數(shù),同樣也可以接收新頁面回傳回來的數(shù)據(jù)。下面我模擬兩個(gè)使用動(dòng)態(tài)路由的場景,既然動(dòng)態(tài)路由可以傳值那就肯定可以不傳值跳頁,我就不模擬動(dòng)態(tài)路由不傳值跳頁的例子了,讀者借助靜態(tài)路由的樣例自行測試即可,我們主要講解一下借助動(dòng)態(tài)路由傳值的例子。
場景三:點(diǎn)擊A頁面中的按鈕,把用戶名跟密碼傳遞給下一個(gè)頁面B頁面,B頁面處理完接收到的數(shù)據(jù)后把結(jié)果回傳給A頁面,A頁面中把從B頁面回傳回來的數(shù)據(jù)顯示在Dialog上。
模擬效果圖

使用動(dòng)態(tài)路由時(shí)我們不再需要像靜態(tài)路由那樣在
MaterialApp中的router中提前注冊(cè)路由路徑,只需要在使用Navigator.push傳入MaterialPageRoute對(duì)象即可
Navigator.push(
context,
new MaterialPageRoute(
//_代表參數(shù)為空
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進(jìn)階之旅"),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
//_代表參數(shù)為空
builder: (_) => new DynamicNaviattionPage(
username: "xiedong",
password: "123456",
))).then((value) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(value),
));
});
},
child: new Text("動(dòng)態(tài)路由傳參"),
)));
}
}
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("動(dòng)態(tài)路由"),
),
body: new Center(
child: new Column(
children: <Widget>[
new MaterialButton(
onPressed: () {
Navigator.pop(context, "未查詢到改該用戶信息");
},
child: new Text("點(diǎn)我返回"),
color: Colors.lightGreen,
),
new Text("上頁傳遞過來的username $username"),
new Text("上頁傳遞過來的password $password"),
],
),
),
);
}
}
關(guān)于路由重點(diǎn)總結(jié)
- Flutter路由分為靜態(tài)路由跟動(dòng)態(tài)路由,靜態(tài)路由不支持向下一個(gè)頁面?zhèn)鬟f參數(shù),動(dòng)態(tài)路由可傳遞
- 靜態(tài)路由使用時(shí)需要提前注冊(cè)聲明頁面路徑,
- 動(dòng)態(tài)路由可以直接在使用時(shí)構(gòu)造路由對(duì)象,不需要提前注冊(cè)路徑。
- 兩種類型都支持接收下一頁面回傳回來的值