快速开始
最简单的使用是用 RoutesLocationBuilder 实现,这种方式产出的代码最少。对于导航场景较少的应用或者页面栈浅的应用(即页面很少堆叠在一起)来说,是很棒的选择。
class MyApp extends StatelessWidget {
final routerDelegate = BeamerDelegate(
locationBuilder: RoutesLocationBuilder(
routes: {
// Return either Widgets or BeamPages if more customization is needed
// 返回 Widgets 或 BeamPages(如果需要更多定制的话)
'/': (context, state, data) => HomeScreen(),
'/books': (context, state, data) => BooksScreen(),
'/books/:bookId': (context, state, data) {
// Take the path parameter of interest from BeamState
// 从 BeamState 获取路径参数
final bookId = state.pathParameters['bookId']!;
// Collect arbitrary data that persists throughout navigation
// 收集在整个导航过程中持续存在的任意数据
final info = (data as MyObject).info;
// Use BeamPage to define custom behavior
// 使用 BeamPage 来自定义行为
return BeamPage(
key: ValueKey('book-$bookId'),
title: 'A Book #$bookId',
popToNamed: '/',
type: BeamPageType.scaleTransition,
child: BookDetailsScreen(bookId, info),
);
}
},
),
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: BeamerParser(),
routerDelegate: routerDelegate,
);
}
}
RoutesLocationBuilder 会根据路径对 routes 进行选择和排序。 例如,导航到 /books/1 会匹配 routes 里的全部3个实体,然后把它们堆叠在一起。导航到 /books 会匹配routes 的前两个实体。
对应的页面被放入到 Navigator.pages 中,BeamerDelegate (重新)构建 Navigator ,在屏幕上显示选中的页面栈。
为什么我们有一个 locationBuilder ? BeamLocation 是什么?它的输出是什么?
BeamLocation 是一个实体,它基于它的 state 来决定哪个页面要进入到 Navigator.pages 里。locationBuilder 选择适当的 BeamLocation 来进一步处理收到的 RouteInformation 。 这大多数是通过验证 BeamLocation.pathPatterns 来实现。
RoutesLocationBuilder 返回 BeamLocation 的一个特殊类型 - RoutesBeamLocation,它有用于绝大多数常用的导航场景的实现。 如果 RoutesLocationBuilder 没有提供所需的行为或者足够的定制,可以扩展 BeamLocation 为进入到 Navigator.pages 的任意数量的页面栈来定义和组织行为。
深入阅读: BeamLocation [中文],BeamState[中文]。
导航
导航是用 “beam” 来完成的。可以认为是在应用中传送(beam)到其它地方。 类似于 Navigator.of(context).pushReplacementNamed('/my-route'),但是 Beamer 并不限于单个页面,或者是推入栈本身。 BeamLocation 创建页面的栈,当 beam 到某个页面时,页面会被构建。 Beaming 感觉像是同时使用了多个 Navigator 的 push/pop (入栈/出栈)方法。
// Basic beaming
Beamer.of(context).beamToNamed('/books/2');
// Beaming with an extension method on BuildContext
// 使用 BuildContext 的扩展方法 Beaming
context.beamToNamed('/books/2');
// Beaming with additional data that persist
// throughout navigation withing the same BeamLocation
// 用同一个 BeamLocation 的导航过程中的数据 Beaming。
context.beamToNamed('/book/2', data: MyObject());
导航返回
这里有两种返回的类型,即 reverse navigation(反转导航); 向上 和 反转时序.
向上 (从栈中弹出页面)
向上导航是指导航到当前页面栈的前一个页面。就是大家熟知的弹出,通过 Navigator 的 pop/maybePop 方法来完成。如果不指定其它处理,默认的 AppBar 的 BackButton 返回按钮会调用这个方法。
Navigator.of(context).maybePop();
反转时序 ( beam 到前一个状态)
反转时序导航会导航到前面访问过的任意地方。在深度链接的情况(例如:从 /authors/3 导航到 /books/2,而不是从 /books 导航到 /books/2)下,这和弹出是不一样的。 Beamer 在 beamingHistory 历史中保持着导航历史,所以它能够导航到 beamingHistory 中的前一个时间点的入口。这称作 “beam back” (回光返照?皮一下)。
Beamer.of(context).beamBack();
Android 返回按键
集成 beam 的 Android 返回按键通过在 MaterialApp.router 中设置 backButtonDispatcher 来实现。这个分发器需要指向同一个为routerDelegate 设置的 BeamerDelegate 的引用。
MaterialApp.router(
...
routerDelegate: beamerDelegate,
backButtonDispatcher: BeamerBackButtonDispatcher(delegate: beamerDelegate),
)
BeamerBackButtonDispatcher 会首先尝试 pop (弹出),如果弹出不可用,会改为 beamBack 。如果 beamBack 返回 false (没有地方可返回),Android 的返回按钮会关闭应用,也可能是返回前一个使用的应用(通过 deep-link (深度链接)打开当前应用)。 BeamerBackButtonDispatcher 可以配置为 alwaysBeamBack (意思是不会尝试 pop (弹出))或 fallbackToBeamBack (意思是不会尝试 beamBack)。
访问最近的 Beamer
要在组件中访问路由的属性(例如,用于构建 BookDetailsScreen 的 bookId )可以使用:
@override
Widget build(BuildContext context) {
final beamState = Beamer.of(context).currentBeamLocation.state as BeamState;
final bookId = beamState.pathParameters['bookId'];
...
}
使用 “Navigator 1.0”
注意 “Navigator 1.0”(命令式的 push/pop 和类似的函数)可以和 Beamer 一起使用。我们已经看到 Navigator.pop 用来向上导航。这告诉我们是在使用同样的 Navigator ,只是使用了不同的 API 。
用 Navigator.of(context).push (或任何类似的动作) 入栈不会反映到 BeamLocation 的状态,这意味着浏览器的 URL 不会改变。可以通过 Beamer.of(context).updateRouteInformation(...) 来只更新 URL 。当然在移动端使用 Beamer 时不会有这个问题,因为看不到 URL 。
通常,每个导航场景应该是可实现的声明式(定义页面栈),而不是命令式(入栈),但是做到这一点的难度会有所不同。
对于中级和高级的用法,现在介绍一些核心概念: BeamLocation 和 BeamState 。
核心概念
从最顶层来看,Beamer 是 Router 的包装,它使用 了自身的对 RouterDelegate 和 RouteInformationParser 的实现。Beamer 的目标是分离【用不同的状态为 Navigator.pages 的多个类来构建页面栈】的职责,代替所有页面栈使用一个全局状态。
例如,我们想要处理所有个人资料相关的页面栈如:
[ ProfilePage ] (个人资料页面),
[ ProfilePage, FriendsPage](个人资料页面,好友页面),
[ ProfilePage, FriendsPage, FriendDetailsPage ](个人资料页面,好友页面,好友详细页面),
[ ProfilePage, SettingsPage ](个人资料页面,设定页面),
…
用一些 “ProfileHandler” 来知道哪个状态对应哪个页面栈。类似地,我们想要一个 “ShopHandler” 来处理所有商店关联的页面栈。这些页面如:
[ ShopPage ](商店页面),
[ ShopPage, CategoriesPage ](商店页面,品类页面),
[ ShopPage, CategoriesPage, ItemsPage ](商店页面,品类页面,商品页面),
[ ShopPage, CategoriesPage, ItemsPage, ItemDetailsPage ](商店页面,品类页面,商品页面,商品详细页面),
[ ShopPage, ItemsPage, ItemDetailsPage ](商店页面,商品
相关阅读
发表评论