Flutter路由框架Fluro使用教程详细讲解
作者:唯鹿
1.Navigator使用简介
使用Flutter 的Navigator
导航器可以实现页面的跳转,Navigator
的使用方法简单介绍一下:
页面跳转:
Navigator.push<void>( context, MaterialPageRoute( builder: (BuildContext context) => const MyHomePage(), ), );
页面跳转的同时关闭当前页面(页面替换):
Navigator.pushReplacement<void, void>( context, MaterialPageRoute( builder: (BuildContext context) => const MyHomePage(), ), );
页面跳转的同时关闭到之前的某一个页面:
Navigator.pushAndRemoveUntil<void>( context, MaterialPageRoute( builder: (BuildContext context) => const MyHomePage(), ), (route) => false // ModalRoute.withName('/') );
也可以直接使用路由名称进行上面操作,例如跳转:Navigator.pushNamed(context, '/home');
路由名称需要提前在MaterialApp
中定义好。
MaterialApp( title: 'Flutter Demo', home: MyHomePage(), routes: { "/page1": (context) => PageA(), "/page2": (context) => PageB(), }, );
接收参数:var args = ModalRoute.of(context).settings.arguments;
页面返回
Navigator.pop(context);
接收页面的返回值:
Navigator.push<void>( context, MaterialPageRoute( builder: (BuildContext context) => const MyHomePage(), ), ).then((dynamic result) { // 页面返回result });
必须同时配合Navigator.pop<dynamic>(context, result);
还有路由删除removeRoute
,路由替换replace
等。
2.fluro
直接使用Navigator
的主要问题是不易维护。如果某个页面的传参发生了变化,那么所有跳转处都需要做修改。
所以我们可以使用现有封装好的路由框架来替我们解决这些问题。比如fluro。
1.配置
添加依赖至pubspec.yaml
:
dependencies: fluro: ^2.0.3
定义唯一一个FluroRouter
对象:
static final FluroRouter router = FluroRouter();
剩下的就是添加路由处理器Handler
,下面代码举例添加了两个页面:
class Routes { static String home = '/home'; static String webViewPage = '/webView'; static final List<IRouterProvider> _listRouter = []; static final FluroRouter router = FluroRouter(); static void initRoutes() { /// 指定路由跳转错误返回页 router.notFoundHandler = Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) { debugPrint('未找到目标页'); return const NotFoundPage(); }); router.define(home, handler: Handler( handlerFunc: (BuildContext? context, Map<String, List<String>> params) => const Home())); // Routes.router.navigateTo(context, '${Routes.webViewPage}?title=标题&url=地址'); router.define(webViewPage, handler: Handler(handlerFunc: (_, params) { /// 接收参数 final String title = params['title']?.first ?? ''; final String url = params['url']?.first ?? ''; return WebViewPage(title: title, url: url); })); } }
配置fluro:
MaterialApp( onGenerateRoute: Routes.router.generator, );
初始化:
class MyApp extends StatelessWidget { MyApp() { Routes.initRoutes(); } ... }
2.使用方法
核心就一个方法navigateTo
,源码如下:
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}) { RouteMatch routeMatch = matchRoute(context, path, transitionType: transition, transitionsBuilder: transitionBuilder, transitionDuration: transitionDuration, maintainState: maintainState, routeSettings: routeSettings); Route<dynamic>? route = routeMatch.route; Completer completer = Completer(); Future future = completer.future; if (routeMatch.matchType == RouteMatchType.nonVisual) { completer.complete("Non visual route type."); } else { ///找不到时走`notFoundHandler` if (route == null && notFoundHandler != null) { route = _notFoundRoute(context, path, maintainState: maintainState); } if (route != null) { final navigator = Navigator.of(context, rootNavigator: rootNavigator); if (clearStack) { future = navigator.pushAndRemoveUntil(route, (check) => false); } else { future = replace ? navigator.pushReplacement(route) : navigator.push(route); } completer.complete(); } else { final error = "No registered route was found to handle '$path'."; print(error); completer.completeError(RouteNotFoundException(error, path)); } } return future; }
path
:路由名称。replace
:等同于pushReplacement
。clearStack
:等同于pushAndRemoveUntil
。transition
:页面跳转动画,默认native,平台默认动画。transitionDuration
:动画时长。transitionBuilder
:自定义动画。routeSettings
:用于传递数据。可使用context.settings.arguments
获取。
具体的使用见项目routers目录。
3.路由拦截
路由拦截可以实现权限控制。比如用户没有登录,当进入某些需要登录后才能显示的页面时,可以拦截跳转进行判断,引导用户进入登录页。
MaterialApp有 onGenerateRoute
方法可以在跳转时进行路由拦截。但是使用的fluro将这一属性占用了,所以我们可以继承 FluroRouter
类,重写navigateTo
方法实现。
class MyFluroRouter extends FluroRouter { List<String> _loginList; set loginList(value) => _loginList = value; @override Future navigateTo( BuildContext context, String path, { bool replace = false, bool clearStack = false, bool maintainState = true, bool rootNavigator = false, TransitionType transition, Duration transitionDuration, transitionBuilder, RouteSettings routeSettings, }) { String pathToNavigate = path; AppRouteMatch routeMatched = this.match(path); String routePathMatched = routeMatched?.route?.route; if (routePathMatched != null) { //如果页面需要登录,修改路由路径到登录页面 if (_loginList != null && !_loginList.contains(routePathMatched)) { pathToNavigate = '/login‘; } } return super.navigateTo(context, pathToNavigate, replace: replace, clearStack: clearStack, maintainState: maintainState, rootNavigator: rootNavigator, transition: transition, transitionDuration: transitionDuration, transitionBuilder: transitionBuilder, routeSettings: routeSettings); } }
3.封装
fluro工具类:
class NavigatorUtils { static void push(BuildContext context, String path, {bool replace = false, bool clearStack = false, Object? arguments}) { unfocus(); Routes.router.navigateTo(context, path, replace: replace, clearStack: clearStack, transition: TransitionType.native, routeSettings: RouteSettings( arguments: arguments, ), ); } static void pushResult(BuildContext context, String path, Function(Object) function, {bool replace = false, bool clearStack = false, Object? arguments}) { unfocus(); Routes.router.navigateTo(context, path, replace: replace, clearStack: clearStack, transition: TransitionType.native, routeSettings: RouteSettings( arguments: arguments, ), ).then((Object? result) { // 页面返回result为null if (result == null) { return; } function(result); }).catchError((dynamic error) { debugPrint('$error'); }); } /// 返回 static void goBack(BuildContext context) { unfocus(); Navigator.pop(context); } /// 带参数返回 static void goBackWithParams(BuildContext context, Object result) { unfocus(); Navigator.pop<Object>(context, result); } static void unfocus() { FocusManager.instance.primaryFocus?.unfocus(); } }
模块管理:
import 'package:fluro/fluro.dart'; abstract class IRouterProvider { void initRouter(FluroRouter router); }
实现接口:
class LoginRouter implements IRouterProvider{ static String loginPage = '/login'; static String registerPage = '/login/register'; @override void initRouter(FluroRouter router) { router.define(loginPage, handler: Handler(handlerFunc: (_, __) => const LoginPage())); router.define(registerPage, handler: Handler(handlerFunc: (_, __) => const RegisterPage())); } }
各模块初始化,放在Routes的initRoutes中:
/// 各自路由由各自模块管理,统一在此添加初始化 _listRouter.add(LoginRouter()); ... /// 初始化路由 void initRouter(IRouterProvider routerProvider) { routerProvider.initRouter(router); } _listRouter.forEach(initRouter);
目前Flutter团队有维护一款路由框架go_router
(支持Navigator 2.0),但目前有部分功能缺失,比如不支持接收页面的返回值,没有pushAndRemoveUntil
方法。
期待后面功能的完善。但就目前来说,对于Android 和iOS平台开发来说fluro的功能足够使用了。
到此这篇关于Flutter路由框架Fluro使用教程详细讲解的文章就介绍到这了,更多相关Flutter Fluro内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!