简介
大多数应用程序具有多个页面或视图,并且希望将用户从页面平滑过渡到另一个页面。Flutter的路由和导航功能可帮助管理应用中屏幕之间的命名和过渡。
管理多个页面时有两个核心概念和类:Route
和 Navigator
。 一个 route
是一个屏幕或页面的抽象,Navigator
是管理 route
的 Widget
。Navigator
可以通过 route
入栈和出栈来实现页面之间的跳转。
Navigator 导航
遇到的坑
在测试的时候,遇到过一个问题,问题就是在于 void main() => runApp(new IndexPage())
。就是不能用这种写法。
import 'package:flutter/material.dart';
import './item.dart';
void main() => runApp(new IndexPage());
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context){
return new MaterialApp(
title: "测试",
home: new Scaffold(
appBar: new AppBar(title: new Text('第一个界面'),),
body: new Center(
child: new RaisedButton(onPressed: (){
print(context); // IndexPage
Navigator.push(context, new MaterialPageRoute(builder: (context) => new ItemPage() ));
}, child: new Text('跳转'),),
),
),
);
}
}
这里后来看了下官网,MaterialApp的主页成为导航器堆栈底部的路径。然后自己理解是:导航需要有一个根部的堆栈,然后 new MaterialApp(home: new MyAppHome())
这里的 home 就充当了根部。
通过 void main() => runApp(new IndexPage())
就是相对于是一个应用跳转到另外一个应用。
void main() {
runApp(new MaterialApp(home: new MyAppHome()));
}
使用 Navigator.push
就是表示跳转到新的界面, 使用 Navigator.pop
就是返回上一个界面。逻辑其实就是将 一个界面加入到 Navigator 的堆栈中(push操作),然后将这个页面移出 Navigator 的堆栈(pop操作)。
在使用 Navigator.push
与 Navigator.pop
的时候,需要传入一个参数 context
, 这个参数值表示当前的界面 。
完整代码实例
import 'package:flutter/material.dart';
/// 跳转到新页面并返回
void main() {
runApp(new MaterialApp(
title: "测试", //application名字
home: new IndexPage(), //初始化页面
));
}
/// 第一个页面
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: new Text("第一个页面") ),
body: new Center(
child: new RaisedButton(
child: new Text("点击跳转"),
onPressed: () {
print(context); // 打印值:IndexPage
//跳转到新的 页面我们需要调用 navigator.push方法
Navigator.push(
context,
new MaterialPageRoute( builder: (context) => new ItemPage()) );
}),
),
);
}
}
/// 第二个页面
class ItemPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar( title: new Text("第二个页面") ),
body: new Center(
//onPressed 点击事件
child: new RaisedButton(
child: new Text("点我回第一个页面"),
onPressed: () {
//回到上一个页面 相当于finsh
Navigator.pop(context);
}
),
),
);
}
}
使用下面这种方式也是可以实现
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
// home 的值必须为 new PageName(), 这样子才能让 home 成为导航器堆栈底部的路径
home: new IndexPage(title: '应用程序首页'),
);
}
}
跳转的方法可以独立出来,下面的写法也是可以的,使用 Navigator.of(context).push
。
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context){
// 点击跳转的方法
_onPressed(){
// Navigator.push(context, new MaterialPageRoute(builder: (context) => new ItemPage() ));
Navigator.of(context).push(new MaterialPageRoute(builder: (context) => new ItemPage() ));
}
return new Scaffold(
appBar: new AppBar(title: new Text('第一个界面'),),
body: new Center(
// 将点击的方法单独出去
child: new RaisedButton(onPressed:_onPressed, child: new Text('跳转'),),
),
);
}
}
使用命名的路由导航
简单的理解就是说,将对应的路由定义在一个路由表中 Map<String, WidgetBuilder>
,类似于'/a/b/c'
。
void main() {
runApp(new MaterialApp(
home: new MyAppHome(), // becomes the route named '/'
// 设置路由表
// 访问 /a 就会跳转到 MyPage1 页面
// 访问 /b 就会跳转到 MyPage2 页面
// 访问 /c 就会跳转到 MyPage3 页面
routes: <String, WidgetBuilder> {
'/a': (BuildContext context) => new MyPage1(title: 'page A'),
'/b': (BuildContext context) => new MyPage2(title: 'page B'),
'/c': (BuildContext context) => new MyPage3(title: 'page C'),
},
));
}
跳转到某个路由
Navigator.pushNamed(context, '/b');
完整的代码实例
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "测试",
home: new IndexPage(),
// 添加路由表
routes: <String, WidgetBuilder> {
'/a' : (BuildContext context) => new IndexPage(),
'/b' : (BuildContext context) => new ItemPage(),
},
));
}
class IndexPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("第一个界面"), ),
body: new Center(
child: new RaisedButton(onPressed: (){
// 使用 Navigator.pushNamed(context, '/a') 跳转
Navigator.pushNamed(context, '/b');
}, child: new Text("点击跳转到第二个界面"),),
)
);
}
}
class ItemPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("第二个界面"), ),
body: new Center(
child: new RaisedButton(onPressed: (){
Navigator.pushNamed(context, '/a');
}, child: new Text("点击跳转到第一个界面"),),
)
);
}
}
图示: