依赖
fluro: ^2.0.3
Fluro使用步骤
构建FluroRouter路由实例,单例
FluroRouter 本身已经是单例模式
static final appRouter = FluroRouter();
定义路由路径的处理器(Handler )
用于匹配不同路由路径的处理方法
static Map<String, Handler> pageRoutes = {
'/': Handler(
handlerFunc: (context, Map<String, List<String>> parameters) =>
const HomePage()),
'/category/:id':
Handler(handlerFunc: (context, Map<String, List<String>> parameters) {
String id = parameters['id']?.first ?? '0';
return const CategoryPage(id);
}),
'/detail/:id':
Handler(handlerFunc: (context, Map<String, List<String>> parameters) {
return const DetailPage();
}),
'/login':
Handler(handlerFunc: (context, Map<String, List<String>> parameters) {
return const LoginPage();
})
格式说明:
HandlerFunc 接收上下文 context ,以及携带了路由参数,这个参数是一个Map ,对应路由路径的多个路由参数。例如/dynamic/:id 路由,如果实际路由为/dynamic/1?event=a&event=b ,则 parameters 的格式如下:
{
"id": ["1"],
"event": ["a", "b"]
}
这样其实也只是传递一些简单数据,如果传递复杂数据需要依靠RouteSettings ,后面会封装
路由设置
在 MaterialApp 中把 onGenerateRoute 设置为 FluroRouter.generator 方法来构建系统路由
class AppRoutes {
static final route = FluroRouter();
static setUp() {
route.notFoundHandler =
Handler(handlerFunc: (context, parameters) => const NotFoundPage());
AppPageHandler.pageRoutes.forEach((path, handler) {
route.define(path,
handler: handler, transitionType: TransitionType.inFromRight);
});
}
}
void main() {
AppRoutes.setUp();
runApp(const MyApp());
}
MaterialApp(onGenerateRoute: AppRoutes.route.generator)
路由跳转
Future navigateTo(BuildContext context, String path,
{bool replace = false,
bool clearStack = false,
bool maintainState = true,
bool rootNavigator = false,
TransitionType? transition,
Duration? transitionDuration,
RouteTransitionsBuilder? transitionBuilder,
RouteSettings? routeSettings}) {
AppRoutes.route.navigateTo(context, 'category/$index')
AppRoutes.route.navigateTo(
context, 'category/$index',
routeSettings: const RouteSettings(arguments: category)),
CategoryPage 接收category 参数
@override
Widget build(BuildContext context) {
var arguments = ModalRoute.of(context)?.settings.arguments;
Category? category;
if (arguments != null && arguments is Category) {
category = arguments;
}
...
}
注意不要在initState中获取参数,因为此时页面树还未创建完成
AppRoutes.router.navigateTo(context, nextPath, clearStack: true);
AppRoutes.router.navigateTo(context, homePath, replace: true);
void pop<T>(BuildContext context, [T? result]) =>
Navigator.of(context).pop(result);
AppRouter.appRouter.pop(context)
Fluro优缺点
- 优点
- 使用简单
- 支持大量的路由动画
- 支持路由拦截
- 支持Web 路由格式
- 缺点
- 不支持
Navigator2 - pop方式单一,复杂场景需要依靠
Navigator - 传递大量参数麻烦,需要依靠
RouteSettings - 路由拦截需要自己实现
封装
- 支持复杂参数
- pop支持复杂场景(使用
Navigator 实现) - 自定义重定向(路由拦截)
- github源码
class Bundle {
final Map<String, dynamic> _map = {};
putInt(String k, int v) => _map[k] = v;
int getInt(String k) => _map[k] ?? 0;
putString(String k, String v) => _map[k] = v;
String getString(String k) => _map[k] ?? '';
putBool(String k, bool v) => _map[k] = v;
bool getBool(String k) => _map[k] ?? false;
putList<T>(String k, List<T> v) => _map[k] = v;
List<T> getList<T>(String k) => _map[k] ?? [];
putMap(String k, Map v) => _map[k] = v;
Map getMap(String k) => _map[k] ?? {};
put<T>(String k, T t) => _map[k] = t;
T? get<T>(String k) => _map[k];
@override
String toString() {
return _map.toString();
}
}
class _AppRouter extends FluroRouter {
@override
Future navigateTo(BuildContext context, String path,
{bool replace = false,
bool clearStack = false,
bool maintainState = true,
bool rootNavigator = false,
RedirectInterceptor? interceptor,
String? name,
Bundle? bundle,
TransitionType? transition,
Duration? transitionDuration,
RouteTransitionsBuilder? transitionBuilder,
RouteSettings? routeSettings}) {
if (interceptor?.needRedirect() ?? false) {
return interceptor!.navigateTo(context);
}
if (bundle != null) {
routeSettings = RouteSettings(arguments: bundle, name: name ?? path);
}
return super.navigateTo(context, path,
replace: replace,
clearStack: clearStack,
maintainState: maintainState,
rootNavigator: rootNavigator,
transition: transition,
transitionDuration: transitionDuration,
transitionBuilder: transitionBuilder,
routeSettings: routeSettings);
}
void popToHome(BuildContext context) {
popUntil(context, (route) => route.isFirst);
}
@override
void pop<T>(BuildContext context, [T? result]) {
if (canPop(context)) {
super.pop(context, result);
}
}
void popUntil(BuildContext context, RoutePredicate predicate) {
Navigator.popUntil(context, predicate);
}
bool canPop(BuildContext context) {
return Navigator.canPop(context);
}
}
final AppRouter = _AppRouter();
abstract class RedirectInterceptor {
bool needRedirect();
Future navigateTo(BuildContext context);
}
封装后再使用
class LoginInterceptor extends RedirectInterceptor {
@override
Future navigateTo(BuildContext context) {
return AppRouter.navigateTo(context, AppPagePath.login);
}
@override
bool needRedirect() {
return !AppManager.getInstance().isLogin;
}
}
onPressed: () => AppRouter.navigateTo(context,AppPagePath.settingMessage,
interceptor: LoginInterceptor()),
onTap: () => AppRouter.appRouter.navigateTo(context, AppPagePath.detail,
bundle: Bundle()..put('detail', model)),
复杂场景下的pop
AppRouter.pop(context))
AppRouter.popToHome(context))
-
手动控制保留那些page 只保留首页以及category 页面
AppRouter.popUntil(context, (route) => route.isFirst || route.settings.name == 'category');
-
返回至首页(底部Tab 的第一个page ) 需要使用状态管理比如:Provider
onPressed: () {
context.read<AppTabModel>().curIndex = 0;
AppRouter.popToHome(context);
}),
|