- Flutter 配置 for mac
- Dart 语法基础(一)变量、常量
- Dart 语法基础(二) 类与函数
- Flutter入门 - 1、基础Widget
- Flutter入门 - 2、布局Widget
- Flutter入门 - 3、滚动视图
- Flutter入门 - 4、异步
- Flutter入门 - 5、dio封装使用
- Flutter入门 - 6、Key
- Flutter入门 - 7、Widget -- Element -- RenderObject
- Flutter入门 - 8、状态管理
概述
路由由来已久,例如 iOS 中使用的 URL 解析,遵守URI标准,通过 path 映射 controller,核心就是一个字典(Map),我们也称之为命名路由。在 Flutter 中,使用 Route 进行路由(页面)管理,Navigator进行路由跳转操作。
Navigator
对 Route 进行管理,就是一个栈,和iOS中的 navigationController 类似。
基本跳转
1、获取 Navigator
- Navigator.of(context)
2、push 方法
-
Navigator.of.push
Navigator.of(context).push( // 页面要向被路由统一管理,必须包装为 Route, 但是 Route 是一个抽象类,所以是不能实例化的,一般使用 MaterialPageRoute MaterialPageRoute( builder: (cxt) { return DetailPage("a message from home"); }, ), );
-
Navigator.of().pushNamed
Navigator.of(context).pushNamed("/setting");
-
Navigator.pushNamed()
// 等同于上面 Navigator.pushNamed(context, AboutPage.pageName);
以上三种push 方法,返回值都是 Future ,因此可以等待pop带回来的信息
3、pop方法
- Navigator.of(context).pop
future.then((value) {
// pop 携带回来的信息
print(value);
setState(() {
_message = value;
});
});
4、拦截返回
除了按钮点击可以直接掉 pop 方法之外,我们还可以拦截左上角返回按钮的行为
在 Scaffold 外嵌套 WillPopScope 实现 onWillPop 则可以拦截返回
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
//拦截返回按钮
Navigator.of(context).pop("a detail message");
},
child: Scaffold()
);
}
参数传递
1、普通传递
Navigator.of(context).push 通过构造器的方式传递,一般应用使用路由的话,使用构造器传递参数会比较少
final future = Navigator.of(context).push(
MaterialPageRoute(
builder: (cxt) {
// 传递的是 DetailPage 构造器所需的参数
return DetailPage("a message from home");
},
),
);
2、arguments
pushNamed 通过 arguments 传递参数
// arguments 是 Object 类型,因此可以传递任意参数
Navigator.pushNamed(context, AboutPage.pageName,
arguments: "a message from home");
Route
我们一般使用命名路由的映射关系来统一管理页面
命名路由
一般将路由放在 MaterialApp 中
return MaterialApp(
title: '路由导航',
theme: ThemeData(
primarySwatch: Colors.blue, splashColor: Colors.transparent
),
initialRoute: "/",
routes: {
"/home": (ctx) => HomePage(),
"/detail": (ctx) => DetailPage()
},
);
在开发中,为了让每个页面对应的routeName统一,我们通常会在每个页面定义一个路由常量来使用
class AboutPage extends StatefulWidget {
static const String pageName = "/about";
}
然后可以将路由改为:
routes: {
HomePage.pageName: (cxt) => HomePage(),
AboutPage.pageName: (cxt) => AboutPage()
}
参数获取
之前讲了通过 构造器方式 以及 arguments 传递参数,现在看通过 arguments 传递的参数怎么获取
通过 ModalRoute.of(context).settings.arguments 获取传参
class _AboutPageState extends State<AboutPage> {
@override
Widget build(BuildContext context) {
final _message = ModalRoute.of(context).settings.arguments as String;
...
...
}
}
路由勾子
onGenerateRoute
比如有的页面(DetailPage)有构造方法,但是我们也想通过命名路由的方式进行管理,像之前的
"/detail": (ctx) => DetailPage() 就无法映射,这时候需要使用 onGenerateRoute,其实也就是自己手动去生成路由 MaterialPageRoute 进行管理。
onGenerateRoute: (settings) {
if (settings.name == "/detail") {
return MaterialPageRoute(
builder: (ctx) {
return DetailPage(settings.arguments);
}
);
}
return null;
},
push 的时候则使用 arguments 传递参数
Navigator.pushNamed(context, DetailPage.pageName,
arguments: "a message from home");
onUnknownRoute
错误页面:如果代码里的路由未添加到 routes 里面,则需要做安全防护。
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (cxt) {
//定义一个错误页面 UnknownPage
return UnknownPage();
},
);
}
路由管理类
路由通常放在一个单独的类中去管理,这样防止 main.dart 中代码堆积
定义 Routes 类,创建静态方法
- routes
- initialRoute
- onGenerateRoute
- onUnknownRoute
在main.dart 里就简化成
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
// 所有路由
routes: Routes.routes,
//启动页 初始页 "/" == HomePage
initialRoute: Routes.initialRoute,
// 勾子路由, 因为页面必须构造器初始化,所以需要在此拦截自己手动生成 Route
onGenerateRoute: Routes.onGenerateRoute,
// 路由找不到的错误页面
onUnknownRoute: Routes.onUnknownRoute,
);
}
}
附 Routes 类中代码:
class Routes {
static final Map<String, WidgetBuilder> routes = {
// "/about" : (cxt) => AboutPage(),
AboutPage.pageName: (cxt) => AboutPage(),
// DetailPage.pageName:(cxt) => DetailPage()
HomePage.pageName: (cxt) => HomePage()
};
static final String initialRoute = HomePage.pageName;
static RouteFactory onGenerateRoute = (settings) {
if (settings.name == DetailPage.pageName) {
return MaterialPageRoute(
builder: (cxt) {
return DetailPage(settings.arguments);
},
);
}
return null;
};
static RouteFactory onUnknownRoute = (settings) {
return MaterialPageRoute(
builder: (cxt) {
return UnknownPage();
},
);
};
}