前言
在Android開發中我們使用Intent來進行頁面跳轉,也稱之為原生路由,後來出現了一些路由框架,比如ARouter。
在Flutter中進行介面跳轉的就是路由,路由用Route類來進行表示,Navigator是對Route進行管理的Widget。這一篇文章我們來學習路由和資料傳遞。flutter路由的使用方式主要有兩種,一種是新建路由,一種是註冊路由。
1.新建路由
建立兩個頁面,第一個頁面有一個按鈕,點選這個按鈕跳到第二個頁面。先來實現第一個頁面:
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(), maintainState: false));
},
),
),
);
}
}
通過Navigator.push()方法將一個Route物件新增到Navigator管理的Route堆疊中,這裡的Route物件是一個MaterialPageRoute,它自帶頁面切換動畫,並且適配了Android和iOS,如果是Android,頁面進入動畫是向上滑動並淡出,退出是相反的;如果是iOS,頁面進入動畫是從右側滑入,退出同樣是相反的。一般來說使用MaterialPageRoute就夠用了,如果不滿足需求,可以實現自定義Route。
接著來實現第二個頁面,程式碼如下所示。
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二頁"),
),
body: Center(
child: RaisedButton(
child: Text("返回到第二頁"),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
Navigator.pop()方法用於關閉當前頁面,返回上一個頁面,並將當前的Route物件從Navigator管理的Route 堆中移除。
完整的程式碼如下所示。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
maintainState: false,
),
);
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二頁"),
),
body: Center(
child: RaisedButton(
child: Text("返回到第二頁"),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
執行程式,效果如下所示。
2.使用註冊路由
如果很多頁面都跳轉到了同一個頁面,每次都要新建路由,那麼會寫很多重複的程式碼,使用註冊路由就可以簡化。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
initialRoute: '/First',//1
routes: {
'/First': (context) => FirstPage(),
"/Second": (context) => SecondPage()
},
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
Navigator.pushNamed(context, '/Second');//2
},
),
),
);
}
}
...
省略了第二頁的程式碼,因為沒有什麼變化。改變的是我們需要定義路由表,路由表的格式為Map<String, WidgetBuilder> routes;
其中key為路由名稱,value是builder回撥函式,用於生成相應的路由Widget。通過路由名稱入棧新路由時,應用會根據路由名稱在路由表中找到對應的WidgetBuilder回撥函式,通過呼叫該回撥函式生成路由widget並返回。
註釋1處用來定義初始路由的頁面,接著註冊路由表,裡面包含了兩個頁面,分別是FirstPage和SecondPage。
註釋2處通過路由名稱來開啟SecondPage。
3.路由間資料傳遞
頁面跳轉的時候經常需要傳遞資料,一般有兩種情況,一種是頁面跳轉資料傳遞,另一種是頁面跳轉返回資料,這裡分別來進行介紹。
3.1 頁面跳轉資料傳遞
一個頁面跳轉到一個新的頁面資料傳遞的方式主要有以下兩種:
- 通過 Navigator.push() 或者 Navigator.pushNamed() 方法傳遞資料
- 通過Widget的建構函式傳遞資料
一般來說會使用第一種方式,下面來進行舉例。
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
Navigator.pushNamed(context, '/Second',arguments: CustomArgumnets('Android進階之光'));
},
),
),
);
}
}
class CustomArgumnets {
String content;
PassArgumnets(this.content);
}
我們通過arguments屬性來傳遞引數,這裡自定義了一個CustomArgumnets,用來傳遞引數。
改寫第一小節SecondPage的程式碼用來獲取資料,如下所示。
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("第二頁"),
),
body: Center(
child: Column(
children: <Widget>[
Text('第一頁的資料為:'),
Text(customArgumnets.content),
RaisedButton(
onPressed: () {
Navigator.pop(context);//1
},
child: Text('返回第一頁'),
),
],
),
),
);
}
}
執行程式碼,跳轉到第二頁,效果如下所示。
3.2 頁面跳轉返回資料
除了頁面跳轉需要傳遞資料,有時還需要從第二個頁面返回資料,改寫3.1小節的SecondPage註釋1處的程式碼。
Navigator.pop(context,CustomArgumnets('Android進階解密'));
接著改寫FirstPage,如下所示。
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
_navigateToSecondPage(context);
},
),
),
);
}
_navigateToSecondPage(BuildContext context) async {
dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
arguments: CustomArgumnets('Android進階之光'));//1
print(customArgumnets.content);
}
}
註釋1處的程式碼可以接java收返回的結果,並且使用非同步來防止阻塞UI。最後貼上完整的程式碼。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
initialRoute: '/First',
routes: {
'/First': (context) => FirstPage(),
"/Second": (context) => SecondPage()
},
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一頁"),
),
body: Center(
child: RaisedButton(
child: Text("跳轉到第二頁"),
onPressed: () {
_navigateToSecondPage(context);
},
),
),
);
}
_navigateToSecondPage(BuildContext context) async {
dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
arguments: CustomArgumnets('Android進階之光'));
print(customArgumnets.content);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("第二頁"),
),
body: Center(
child: Column(
children: <Widget>[
Text('第一頁的資料為:'),
Text(customArgumnets.content),
RaisedButton(
onPressed: () {
Navigator.pop(context,CustomArgumnets('Android進階解密'));
},
child: Text('返回第一頁'),
),
],
),
),
);
}
}
class CustomArgumnets {
String content;
CustomArgumnets(this.content);
}
執行程式,當我們點選返回第一頁,在控制檯中會列印出 Android進階解密。
By: Laravel-China 寧澤林
MyBlog: nizer.in