Flutter路由框架Fluro使用教程詳細(xì)講解
1.Navigator使用簡(jiǎn)介
使用Flutter 的Navigator 導(dǎo)航器可以實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn),Navigator的使用方法簡(jiǎn)單介紹一下:
頁(yè)面跳轉(zhuǎn):
Navigator.push<void>(
context,
MaterialPageRoute(
builder: (BuildContext context) => const MyHomePage(),
),
);
頁(yè)面跳轉(zhuǎn)的同時(shí)關(guān)閉當(dāng)前頁(yè)面(頁(yè)面替換):
Navigator.pushReplacement<void, void>(
context,
MaterialPageRoute(
builder: (BuildContext context) => const MyHomePage(),
),
);
頁(yè)面跳轉(zhuǎn)的同時(shí)關(guān)閉到之前的某一個(gè)頁(yè)面:
Navigator.pushAndRemoveUntil<void>(
context,
MaterialPageRoute(
builder: (BuildContext context) => const MyHomePage(),
),
(route) => false // ModalRoute.withName('/')
);
也可以直接使用路由名稱進(jìn)行上面操作,例如跳轉(zhuǎn):Navigator.pushNamed(context, '/home');路由名稱需要提前在MaterialApp中定義好。
MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
routes: {
"/page1": (context) => PageA(),
"/page2": (context) => PageB(),
},
);
接收參數(shù):var args = ModalRoute.of(context).settings.arguments;
頁(yè)面返回
Navigator.pop(context);
接收頁(yè)面的返回值:
Navigator.push<void>(
context,
MaterialPageRoute(
builder: (BuildContext context) => const MyHomePage(),
),
).then((dynamic result) {
// 頁(yè)面返回result
});
必須同時(shí)配合Navigator.pop<dynamic>(context, result);
還有路由刪除removeRoute,路由替換replace等。
2.fluro
直接使用Navigator的主要問(wèn)題是不易維護(hù)。如果某個(gè)頁(yè)面的傳參發(fā)生了變化,那么所有跳轉(zhuǎn)處都需要做修改。
所以我們可以使用現(xiàn)有封裝好的路由框架來(lái)替我們解決這些問(wèn)題。比如fluro。
1.配置
添加依賴至pubspec.yaml:
dependencies: fluro: ^2.0.3
定義唯一一個(gè)FluroRouter對(duì)象:
static final FluroRouter router = FluroRouter();
剩下的就是添加路由處理器Handler,下面代碼舉例添加了兩個(gè)頁(yè)面:
class Routes {
static String home = '/home';
static String webViewPage = '/webView';
static final List<IRouterProvider> _listRouter = [];
static final FluroRouter router = FluroRouter();
static void initRoutes() {
/// 指定路由跳轉(zhuǎn)錯(cuò)誤返回頁(yè)
router.notFoundHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
debugPrint('未找到目標(biāo)頁(yè)');
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=標(biāo)題&url=地址');
router.define(webViewPage, handler: Handler(handlerFunc: (_, params) {
/// 接收參數(shù)
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.使用方法
核心就一個(gè)方法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 {
///找不到時(shí)走`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:頁(yè)面跳轉(zhuǎn)動(dòng)畫,默認(rèn)native,平臺(tái)默認(rèn)動(dòng)畫。transitionDuration:動(dòng)畫時(shí)長(zhǎng)。transitionBuilder:自定義動(dòng)畫。routeSettings:用于傳遞數(shù)據(jù)??墒褂?code>context.settings.arguments獲取。
具體的使用見項(xiàng)目routers目錄。
3.路由攔截
路由攔截可以實(shí)現(xiàn)權(quán)限控制。比如用戶沒有登錄,當(dāng)進(jìn)入某些需要登錄后才能顯示的頁(yè)面時(shí),可以攔截跳轉(zhuǎn)進(jìn)行判斷,引導(dǎo)用戶進(jìn)入登錄頁(yè)。
MaterialApp有 onGenerateRoute方法可以在跳轉(zhuǎn)時(shí)進(jìn)行路由攔截。但是使用的fluro將這一屬性占用了,所以我們可以繼承 FluroRouter 類,重寫navigateTo方法實(shí)現(xiàn)。
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) {
//如果頁(yè)面需要登錄,修改路由路徑到登錄頁(yè)面
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) {
// 頁(yè)面返回result為null
if (result == null) {
return;
}
function(result);
}).catchError((dynamic error) {
debugPrint('$error');
});
}
/// 返回
static void goBack(BuildContext context) {
unfocus();
Navigator.pop(context);
}
/// 帶參數(shù)返回
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);
}
實(shí)現(xiàn)接口:
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中:
/// 各自路由由各自模塊管理,統(tǒng)一在此添加初始化
_listRouter.add(LoginRouter());
...
/// 初始化路由
void initRouter(IRouterProvider routerProvider) {
routerProvider.initRouter(router);
}
_listRouter.forEach(initRouter);目前Flutter團(tuán)隊(duì)有維護(hù)一款路由框架go_router(支持Navigator 2.0),但目前有部分功能缺失,比如不支持接收頁(yè)面的返回值,沒有pushAndRemoveUntil方法。
期待后面功能的完善。但就目前來(lái)說(shuō),對(duì)于Android 和iOS平臺(tái)開發(fā)來(lái)說(shuō)fluro的功能足夠使用了。
到此這篇關(guān)于Flutter路由框架Fluro使用教程詳細(xì)講解的文章就介紹到這了,更多相關(guān)Flutter Fluro內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android SwipeRefreshLayout下拉刷新源碼解析
這篇文章主要為大家詳細(xì)解析了Android SwipeRefreshLayout下拉刷新源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android 控件(button)對(duì)齊方法實(shí)現(xiàn)詳解
horizontal是讓所有的子元素按水平方向從左到右排列,vertical是讓所有的子元素按豎直方向從上到下排列,下面為大家介紹下控件(button)的對(duì)齊方法2013-06-06
詳解ListView中多種item的實(shí)現(xiàn)方式
這篇文章主要給大家介紹了關(guān)于ListView中多種item的實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的很詳細(xì),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-12-12
Android build.gradle版本名打包配置的方法
這篇文章主要介紹了Android build.gradle版本名打包配置的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
Android底部導(dǎo)航欄的三種風(fēng)格實(shí)現(xiàn)
這篇文章主要介紹了Android底部導(dǎo)航欄的三種風(fēng)格實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Android應(yīng)用開發(fā)中CardView的初步使用指南
這篇文章主要介紹了Android應(yīng)用開發(fā)中CardView的初步使用指南,CardView主要處理一些卡片型的視圖布局,需要的朋友可以參考下2016-02-02
Kotlin協(xié)程之Flow觸發(fā)與消費(fèi)示例解析
Kotlin協(xié)程中,當(dāng)需要消費(fèi)流時(shí),會(huì)調(diào)用collect方法,觸發(fā)流的消費(fèi),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09
基于android中的各種顏色在drawable.xml中的值詳解
本篇文章是對(duì)在android中的各種顏色在drawable.xml中的值進(jìn)行了詳細(xì)的介紹。需要的朋友參考下2013-05-05
android加載系統(tǒng)相冊(cè)圖片并顯示詳解
大家好,本篇文章主要講的是android加載系統(tǒng)相冊(cè)圖片并顯示詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12

