深色模式
Flutter路由库go_router
介绍
go_router是Flutter官方推荐的路由库。
TIP
如果仅使用Flutter开发中小型移动端App,不使用GoRouter也能满足需求。
简单使用
创建一个GoRouter
对象:
dart
import 'package:go_router/go_router.dart';
final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
],
);
在MaterialApp
中使用它:
dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
);
}
}
动态路由
使用GoRouter.routingConfig()
构造函数来创建GoRouter
对象,此构造函数的参数是一个ValueNotifier
,所以,能通过改变这个ValueNotifier
的value
,来更新路由配置,实现动态路由。
使用GoRouter.routingConfig()
:
dart
final ValueNotifier<RoutingConfig> myRoutingConfig = ValueNotifier<RoutingConfig>(
RoutingConfig(
routes: <RouteBase>[GoRoute(path: '/', builder: (_, __) => HomeScreen())],
),
);
final GoRouter router = GoRouter.routingConfig(routingConfig: myRoutingConfig);
动态改变:
dart
myRoutingConfig.value = RoutingConfig(
routes: <RouteBase>[
GoRoute(path: '/', builder: (_, __) => AlternativeHomeScreen()),
GoRoute(path: '/a-new-route', builder: (_, __) => SomeScreen()),
],
);
但是,如果项目中使用了全局状态管理,则不必使用ValueNotifier
的方式了,直接在GoRouter
中读取全局状态,当状态改变时,路由也能动态改变,这样的方式,更符合Flutter响应式、声明式的思想。
下面举例,假如需要根据用户登录状态、用户权限动态生成路由
将GoRouter
定义在全局状态中(这里使用了RiverPod,其它的也可以):
dart
@riverpod
class Router extends _$Router {
@override
GoRouter build() {
var loginAsync = ref.watch(loginInfoProvider);
final authorized = switch (loginAsync) {
AsyncData(value: final loginBean) => loginBean.token.isNotEmpty,
_ => false,
};
final permission = switch (loginAsync) {
AsyncData(value: final loginBean) => loginBean.token.isNotEmpty ? loginBean.permission : 0,
_ => 0,
};
final routes = _dynamicRoutes(permission); // 动态创建路由列表
final router = GoRouter(
routes: routes,
);
return router;
}
}
读取GoRouter
,在MaterialApp
中使用它:
dart
final router = ref.watch(routerProvider);
return MaterialApp.router(
routerConfig: router,
);
当全局状态改变时,路由也会改变。
嵌套导航
可以使用ShellRoute
,实现移动端Tab导航,或web端菜单导航的效果。
dart
ShellRoute(
builder: (BuildContext context, GoRouterState state, Widget child) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar( /* ... */ ),
);
},
routes: <RouteBase>[
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) {
return const DetailsScreen();
},
),
],
),
类型安全
可以使用go_router_builder代码生成工具。
重定向
重定向回调函数,有2种级别:
- 顶级重定向:每次导航时都会触发
- 路由级重定向:导航到此路由时,触发
在回调函数中,返回null
或原目标导航的path
,代表不重定向,返回其它path
,代表要重定向。
dart
redirect: (BuildContext context, GoRouterState state) {
if (!AuthState.of(context).isSignedIn) {
return '/signin';
} else {
return null;
}
},
导航动画
使用GoRoute
中的pageBuilder
,而不是builder
:
dart
GoRoute(
path: 'details',
pageBuilder: (context, state) {
return CustomTransitionPage(
key: state.pageKey,
child: DetailsScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation),
child: child,
);
},
);
},
),