开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
本文翻译自: riverpod_navigator | Flutter Package (flutter-io.cn)
译时版本:1.0.10
Riverpod 导航
如果你对该包创建的动机、该包解决了什么问题的详细很感兴趣,可读一下这个中篇文章: 使用 Riverpod 的简易的 Flutter 导航。
使用 riverpod 和 Navigator 2.0 的简易强大的 Flutter 导航解决了下面的问题:
- 严格类型导航:
可以在代码中使用navigate([HomeSegment(),BookSegment(id: 2)]);代替navigate('home/book;id:2'); - 异步导航... ... 是当导航状态的改变需要异步进行(如 从网络加载或保存数据)时的情况。
- 多个 provider... ... 是当导航状态依赖多个 riverpod 的 provider 时。
- 更简单的编码: 导航问题简化为操作类的集合。
- 更好地分离关注点:UI x Model (得益于 riverpod 👍):
导航逻辑可被开发和测试而不需要创建一个简单的 Flutter 组件。 - 嵌套导航
只需要使用 riverpod 的
ProviderScope()和 Flutter 的Router组件。
使用术语
看一下下面和 URL 路径 home/book;id=2 相关的项目。
- 字符串-路径: e.g.
home/book;id=2 - 字符串-段: 字符串-路径 由反斜杠界定的 字符串-段 (
home和book;id=2) 组成 - 类型-段 描述了相应字符串-段 (
HomeSegment()对应 'home' ,BookSegment(id:2)对应 'book;id=2')
类型段 是class TypedSegment {}的派生。 - 类型-路径 描述了相应的 字符串-路径 (
[HomeSegment(), BookSegment(id:2)])
类型-路径 即typedef TypedPath = List<TypedSegment> - Flutter Navigator 2.0 的 导航栈 是由类型路径唯一确定。(每个类型路径的 类型段实例对应一个屏幕和页面实例):
pages = [MaterialPage (child: HomeScreen(HomeSegment())), MaterialPage (child: BookScreen(BookSegment(id:2)))]
简单示例
使用下面的简单几步创建应用:
第 1 步 - 为类型-段定义类
class HomeSegment extends TypedSegment {
const HomeSegment();
factory HomeSegment.decode(UrlPars pars) => const HomeSegment();
}
class BookSegment extends TypedSegment {
const BookSegment({required this.id});
factory BookSegment.decode(UrlPars pars) => BookSegment(id: pars.getInt('id'));
final int id;
@override
void encode(UrlPars pars) => pars.setInt('id', id);
}
encode 和 decncode 用于辅助 类型-段 和 字符串-段 之间的相互转换。
第 2 步 - 配置应用的导航
... 通过继承 RNavigator 类。
class AppNavigator extends RNavigator {
AppNavigator(Ref ref)
: super(
ref,
[
/// 'home' 和 'book' 字符串用在 WEB URL中,例,'home/book;id=2'
/// decode 用于将 URL 解码为 HomeSegment/BookSegment
/// HomeScreen/BookScreen.new 是用于指定段的页面构建器
RRoute<HomeSegment>(
'home',
HomeSegment.decode,
HomeScreen.new,
),
RRoute<BookSegment>(
'book',
BookSegment.decode,
BookScreen.new,
),
],
);
}
第 3 步 - 在MaterialApp.router 中使用 AppNavigator
如果习惯了 Flutter Navigator 2.0 和 riverpod,下面的代码就很清晰了:
class App extends ConsumerWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final navigator = ref.read(navigatorProvider) as AppNavigator;
return MaterialApp.router(
title: 'Riverpod Navigator Example',
routerDelegate: navigator.routerDelegate,
routeInformationParser: navigator.routeInformationParser,
);
}
}
第 4 步 - 配置 riverpod 的 ProviderScope ...
... 在 main 入口处
void main() => runApp(
ProviderScope(
// [HomeSegment()] 作为主页的类型路径,需要导航构造方法
overrides: riverpodNavigatorOverrides([HomeSegment()], AppNavigator.new),
child: const App(),
),
);
第 5 步 - 编写页面组件的代码
有两个页面需要编码:HomeScreen 和 BookScreen。这些页面继承 RScreen 组件。
class BookScreen extends RScreen<AppNavigator, BookSegment> {
const BookScreen(BookSegment segment) : super(segment);
@override
Widget buildScreen(ref, navigator, appBarLeading) => Scaffold(
appBar: AppBar(
title: Text('Book ${segment.id}'),
/// [appBarLeading] 重写标准的后退按钮行为
leading: appBarLeading,
),
body:
...
RScreen 组件:
该组件对于异步导航能正常运行是必需的。
- 替换标准的安卓后退按钮行为(使用 Flutter BackButtonListener 组件)
- 会提供 appBarLeading 图标替换标准的 AppBar 后退按钮行为
然后就完成了。
查看:
[运行示例] 中的链接
Go to book: [3, 13, 103](pavelpz.github.io/doc_simple/) 不会是有实际意义的书籍应用。但他展现了四个页面导航栈的导航:
- 字符串-路径 =
home/book;id=3/book;id=13/book;id=103.- 类型-路径 =
[HomeSegment(), BookSegment(id:3), BookSegment(id:13), BookSegment(id:103)].- 导航-栈 (flutter Navigator.pages) =
[MaterialPage (child: HomeScreen(HomeSegment())), MaterialPage (child: BookScreen(BookSegment(id:3))), MaterialPage (child: BookScreen(BookSegment(id:13))), MaterialPage (child: BookScreen(BookSegment(id:103)))].
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情