The Navigation between Flutter Routes
Navigation 纵览
容易想象到的是,客户端的导航逻辑具有相似性。对具有原生app经验的开发者来说,它可以类比于 native app 开发中的“页面”跳转(Android 中的 Activity
, iOS 中的 ViewController
)。同样UI层面的概念在Flutter也出现了,它就是 Route
其关联的有Widget
, 较为常见的Widget有 StatelessWidget
或是 StatefulWidget
;同时与跳转逻辑相关的还有Navigator
, 而 Navigator
本身也是一个Widget (Flutter中 Widget无处不在!😊),它遵循Stack栈的规则管理着一系列子Widget。
最直接的页面跳转方式
使用 MaterialPageRoute
:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => YourWidget()),
);
Route 利用一个builder方法定义自身的Widget,而非直接传入一个子Widget, 这是因为基于自身被Pushed 或是 Popped的不同context环境下,它会被构建以及重建(built and rebuilt)。
具名的 Route
手机上的App通常会有大量的Route, 而通过名字去找到相应的Route往往也更容易。按照约定Route的名字和路径的表示(path-like structure)比较相像。"/" 用以表示 App 的Home页面的Route。
MaterialApp
在创建的时候可以指定其 routes
(结构为 Map<String, WidgetBuilder>
),它保留了 Route的名字与 创建对应Widget build 方法的映射关系。
MaterialApp(
home: MyAppHome(), // becomes the route named '/'
routes: {
'/a_route_name': (BuildContext context) => YourWidget(),
},
)
按名字显示一个Route :
Navigator.pushNamed(context, '/a_route_name');
参数传递
设置传入参数
同样使用 MaterialPageRoute
,可以设置其可选参数settings
传入参数:
MaterialPageRoute(
builder: (BuildContext context) {
return YourWidget();
},
settings: RouteSettings(arguments: your_param_object),
);
对于具名的Route,类似的方法有:
Navigator.pushNamed(context, routeName, arguments: your_param_object);
读取传入的参数
class MyWidget {
@override
Widget build(BuildContext context) {
final MyArgs args = ModalRoute.of(context).settings.arguments;
// ...
}
}
设置传出的参数
在第2个Widget中 (SelectionScreen
) 设定返回值
Navigator.pop(context, 'Yep!');
在首个Widget中接收:
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
更多 Navigation 相关的方法
Navigator.popAndPushNamed(context, routeName);
Navigator.of(context).pushNamedAndRemoveUntil(HomeScreen.routeName, (_) => false);
Navigator.of(context).pushReplacement(newRoute)