在Android中頁面跳轉使用context.startActivity
,iOS中頁面之間跳轉使用的是ViewController
。在我們Flutter中,頁面之間的跳轉與數據傳遞使用的是Navigator.push
和Navigator.pop
以及Router
。也是比較簡單的,我們一起來使用Navigator+Router
看看如何實現下面的效果。
打開新頁面并且返回
實現下面效果,打開新頁面并且返回到上一級頁面。
- 創建兩個頁面
- Navigator.push(打開頁面)
- Navigator.pop(退出當前頁面)
新建兩個頁面
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text(" Navigator.push SecondPage"),
onPressed: () {
//導航到SecondPage
_navigateSecondPage(context);
})),
);
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text(" Navigator.push ThirdPage"),
onPressed: () {
//退出當前頁面
_backCurrentPage(context);
})),
);
}
}
使用Navigator.push 跳轉到新頁面
Navigator.push(BuildContext context, Route<T> route)
可以將當前頁面轉換成Router
,壓入由Navigator
管理的路由堆棧(the stack of routes)中。
Route
的具體實現如下:
這里我們使用MaterialPageRoute
void _navigateSecondPage(BuildContext context) {
//MaterialPageRoute({
// @required this.builder,
// RouteSettings settings,
// this.maintainState = true,
// bool fullscreenDialog = false,
// })
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
}
使用Navigator.pop退出當前頁面
Navigator.pop(BuildContext context, [ T result ])
,會將當前頁面對應的Router
從Navigator
管理的路由堆棧中移除。
//退出當前頁面,返回到上一級頁面
void _backCurrentPage(BuildContext context) {
Navigator.pop(context);
}
攜帶數據到新的頁面
發送也就是攜帶數據到新頁面也是十分簡單,我們改造下上面的_navigateSecondPage
方法即可。在上面的例子中我們通過return SecondPage()
,可以將數據放入到SecondPage
的構造方法中,這樣打開新頁面的時候數據就自動帶入到了新頁面。例如,我們攜帶String
類型的數據到SecondPage
,可以按照下面的方法來弄。
- 改動
SecondPage
的構造方法
class SecondPage extends StatelessWidget {
final value;
SecondPage({Key key, @required this.value}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("$value"),
onPressed: () {
_backCurrentPage(context);
})),
);
}
}
- 改動
_navigateSecondPage
方法
void _navigateSecondPage(BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage(value: '我是FirstPage帶來的數據');
}));
}
效果如下:
對于頁面之間的跳轉除了上面的方法之外,還可以基于命名路由的方式自由跳轉,下節再講。
返回數據到上一級頁面
- 將要返回的數據放入到
Navigator.pop
中
//退出當前頁面,返回到上一級頁面
void _backCurrentPage(BuildContext context) {
print('執行了_backCurrentPage');
///只有執行了這個方法,上級頁面才會收到返回的數據
Navigator.pop(context, '我是來自SecondPage的數據');
}
- 使用
Navigator.push+async+await
處理返回的數據
/// async關鍵字聲明該函數內部有代碼需要延遲執行
/// 使用await會把延遲運算放入到延遲運算的隊列(await)中。
void _navigateSecondPage(BuildContext context) async {
print('執行了_navigateSecondPage');
final result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
print('FirstPage收到數據:$result');
}
可以看到上一級收到了數據,不過前提是調用了Navigator.pop(context, '我是來自SecondPage的數據');
,直接返回上級頁面,這種情況下,上級頁面是收不到數據的。
完整代碼如下:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("Navigator.push SecondPage"),
onPressed: () {
_navigateSecondPage(context);
})),
);
}
// void _navigateSecondPage(BuildContext context) {
// //MaterialPageRoute({
// // @required this.builder,
// // RouteSettings settings,
// // this.maintainState = true,
// // bool fullscreenDialog = false,
// // })
// Navigator.push(context, MaterialPageRoute(builder: (context) {
// return SecondPage(value: '我是FirstPage帶來的數據');
// }));
// }
/// async關鍵字聲明該函數內部有代碼需要延遲執行
/// 使用await會把延遲運算放入到延遲運算的隊列(await)中。
void _navigateSecondPage(BuildContext context) async {
print('執行了_navigateSecondPage');
final result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
print('FirstPage收到數據:$result');
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("返回數據到FirstPage"),
onPressed: () {
_backCurrentPage(context);
})),
);
}
}
///退出當前頁面,返回到上一級頁面
void _backCurrentPage(BuildContext context) {
print('執行了_backCurrentPage');
///只有執行了這個方法,上級頁面才會收到返回的數據
Navigator.pop(context, '我是來自SecondPage的數據');
}
基于已命名路由調整
除了上述跳轉方式之外,Flutter還支持將路由與頁面對應起來。進行已命名路由的跳轉。這一部分也是比較容易了解的。
import 'package:flutter/material.dart';
class NamedRouter {
static Map<String, WidgetBuilder> routes;
//初始化App
static Widget initApp() {
return MaterialApp(
initialRoute: '/',
routes: NamedRouter.initRoutes(),
);
}
//初始化路由
static initRoutes() {
routes = {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen()
};
return routes;
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
// Navigate to the second screen using a named route
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
//main函數中使用
void main() => runApp(NamedRouter.initApp());
回到開頭,看看如何基于上面的知識實戰實現豆瓣Top150詳情。
代碼地址
Flutter 豆瓣客戶端,誠心開源
Flutter Container
Flutter SafeArea
Flutter Row Column MainAxisAlignment Expanded
Flutter Image全解析
Flutter 常用按鈕總結
Flutter ListView豆瓣電影排行榜
Flutter Card
Flutter Navigator&Router(導航與路由)
OverscrollNotification不起效果引起的Flutter感悟分享
Flutter 上拉抽屜實現
Flutter 豆瓣客戶端,誠心開源
Flutter 更改狀態欄顏色