Flutter上線項(xiàng)目實(shí)戰(zhàn)記錄之路由篇
1. 應(yīng)用場(chǎng)景
開(kāi)發(fā)中經(jīng)常遇到
- 路由跳轉(zhuǎn)時(shí)拿不到context怎么辦,eg: token失效/異地登錄跳轉(zhuǎn)登錄頁(yè)面。
- 獲取不到當(dāng)前路由名稱怎么辦,eg: 點(diǎn)擊push推送跳轉(zhuǎn)指定路由,如果已經(jīng)在當(dāng)前頁(yè)面就replace,如果不在就push。
- 注冊(cè)監(jiān)聽(tīng)路由跳轉(zhuǎn),做一些想做的事情 ,eg:不同路由,顯示不同狀態(tài)欄顏色。
- 等等...
2. 解決方案
解決思路:
- MaterialApp 的routes屬性賦值路由數(shù)組,navigatorObservers屬性賦值路由監(jiān)聽(tīng)對(duì)象NavigatorManager。
- 在NavigatorManager里實(shí)現(xiàn)NavigatorObserver的didPush/didReplace/didPop/didRemove,并記錄到路由棧List _mRoutes中。
- 將實(shí)時(shí)記錄的路由跳轉(zhuǎn),用stream發(fā)一個(gè)廣播,哪里需要哪里注冊(cè)。
3. 具體實(shí)現(xiàn)
main.dart
MaterialApp( navigatorObservers: [NavigatorManager.getInstance()], routes: NavigatorManager.configRoutes, ... )
navigator_manager.dart
class NavigatorManager extends NavigatorObserver {
/* 配置routes */
static Map<String, WidgetBuilder> configRoutes = {
PackageInfoPage.sName: (context) =>
SplashPage.sName: (context) => SplashPage(),
LoginPage.sName: (context) => SplashPage()),
MainPage.sName: (context) => SplashPage(),
//...
}
// 當(dāng)前路由棧
static List<Route> _mRoutes;
List<Route> get routes => _mRoutes;
// 當(dāng)前路由
Route get currentRoute => _mRoutes[_mRoutes.length - 1];
// stream相關(guān)
static StreamController _streamController;
StreamController get streamController=> _streamController;
// 用來(lái)路由跳轉(zhuǎn)
static NavigatorState navigator;
/* 單例給出NavigatorManager */
static NavigatorManager navigatorManager;
static NavigatorManager getInstance() {
if (navigatorManager == null) {
navigatorManager = new NavigatorManager();
_streamController = StreamController.broadcast();
}
return navigatorManager;
}
// replace 頁(yè)面
pushReplacementNamed(String routeName, [WidgetBuilder builder]) {
return navigator.pushReplacement(
CupertinoPageRoute(
builder: builder ?? configRoutes[routeName],
settings: RouteSettings(name: routeName),
),
);
}
// push 頁(yè)面
pushNamed(String routeName, [WidgetBuilder builder]) {
return navigator.push(
CupertinoPageRoute(
builder: builder ?? configRoutes[routeName],
settings: RouteSettings(name: routeName),
),
);
}
// pop 頁(yè)面
pop<T extends Object>([T result]) {
navigator.pop(result);
}
// push一個(gè)頁(yè)面, 移除該頁(yè)面下面所有頁(yè)面
pushNamedAndRemoveUntil(String newRouteName) {
return navigator.pushNamedAndRemoveUntil(newRouteName, (Route<dynamic> route) => false);
}
// 當(dāng)調(diào)用Navigator.push時(shí)回調(diào)
@override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
if (_mRoutes == null) {
_mRoutes = new List<Route>();
}
// 這里過(guò)濾調(diào)push的是dialog的情況
if (route is CupertinoPageRoute || route is MaterialPageRoute) {
_mRoutes.add(route);
routeObserver();
}
}
// 當(dāng)調(diào)用Navigator.replace時(shí)回調(diào)
@override
void didReplace({Route newRoute, Route oldRoute}) {
super.didReplace();
if (newRoute is CupertinoPageRoute || newRoute is MaterialPageRoute) {
_mRoutes.remove(oldRoute);
_mRoutes.add(newRoute);
routeObserver();
}
}
// 當(dāng)調(diào)用Navigator.pop時(shí)回調(diào)
@override
void didPop(Route route, Route previousRoute) {
super.didPop(route, previousRoute);
if (route is CupertinoPageRoute || route is MaterialPageRoute) {
_mRoutes.remove(route);
routeObserver();
}
}
@override
void didRemove(Route removedRoute, Route oldRoute) {
super.didRemove(removedRoute, oldRoute);
if (removedRoute is CupertinoPageRoute || removedRoute is MaterialPageRoute) {
_mRoutes.remove(removedRoute);
routeObserver();
}
}
void routeObserver() {
LogUtil.i(sName, '&&路由棧&&');
LogUtil.i(sName, _mRoutes);
LogUtil.i(sName, '&&當(dāng)前路由&&');
LogUtil.i(sName, _mRoutes[_mRoutes.length - 1]);
// 當(dāng)前頁(yè)面的navigator,用來(lái)路由跳轉(zhuǎn)
navigator = _mRoutes[_mRoutes.length - 1].navigator;
streamController.sink.add(_mRoutes);
}
}
4. 如何使用
token失效跳轉(zhuǎn)
case 401:
ToastUtil.showRed('登錄失效,請(qǐng)重新登陸');
UserDao.clearAll();
NavigatorManager.getInstance().pushNamedAndRemoveUntil(LoginPage.sName);
break;
點(diǎn)擊push推送跳轉(zhuǎn)
static jumpPage(String pageName, [WidgetBuilder builder]) {
String currentRouteName = NavigatorManager.getInstance().currentRoute.settings.name;
// 如果是未登錄,不跳轉(zhuǎn)
if (NavigatorManager.getInstance().routes[0].settings.name != MainPage.sName) {
return;
}
// 如果已經(jīng)是當(dāng)前頁(yè)面就replace
if (currentRouteName == pageName) {
NavigatorManager.getInstance().pushReplacementNamed(pageName, builder);
} else {
NavigatorManager.getInstance().pushNamed(pageName, builder);
}
}
監(jiān)聽(tīng)路由改變狀態(tài)欄顏色
class StatusBarUtil {
static List<String> lightRouteNameList = [
TaskhallPage.sName,
//...
];
static List darkRoutNameList = [
SplashPage.sName,
LoginPage.sName,
MainPage.sName,
//...
];
static init() {
NavigatorManager.getInstance().streamController.stream.listen((state) {
setupStatusBar(state[state.length - 1]);
})
}
setupStatusBar(Route currentRoute) {
if (lightRouteNameList.contains(currentRoute.settings.name)) {
setLight();
} else if (darkRoutNameList.contains(currentRoute.settings.name)) {
setDart();
}
}
}
完結(jié),撒花🎉
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- Flutter路由框架Fluro使用簡(jiǎn)介
- Flutter如何完成路由攔截,實(shí)現(xiàn)權(quán)限管理
- Flutter開(kāi)發(fā)中的路由參數(shù)處理
- Flutter app頁(yè)面路由以及路由攔截的實(shí)現(xiàn)
- 詳解Flutter的路由導(dǎo)航
- flutter 路由跳轉(zhuǎn)的實(shí)現(xiàn)示例
- flutter 自定義websocket路由的實(shí)現(xiàn)
- Flutter開(kāi)發(fā)之路由與導(dǎo)航的實(shí)現(xiàn)
- Flutter利用注解生成可自定義的路由的實(shí)現(xiàn)
- Flutter 局部路由實(shí)現(xiàn)詳解
- Flutter路由的跳轉(zhuǎn)、動(dòng)畫和傳參詳解(最簡(jiǎn)單)
- Flutter 路由插件fluro的使用
相關(guān)文章
使用CMake構(gòu)建OpenCV項(xiàng)目過(guò)程解析
這篇文章主要介紹了使用CMake構(gòu)建OpenCV項(xiàng)目過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Android getViewById和getLayoutInflater().inflate()的詳解及比較
這篇文章主要介紹了Android getViewById和getLayoutInflater().inflate()的詳解及比較的相關(guān)資料,這里對(duì)這兩種方法進(jìn)行了詳細(xì)的對(duì)比,對(duì)于開(kāi)始學(xué)習(xí)Android的朋友使用這兩種方法是個(gè)很好的資料,需要的朋友可以參考下2016-11-11
Android編程實(shí)現(xiàn)ActionBar的home圖標(biāo)動(dòng)畫切換效果
這篇文章主要介紹了Android編程實(shí)現(xiàn)ActionBar的home圖標(biāo)動(dòng)畫切換效果,涉及Android布局、樣式、Activity及菜單相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
Android自動(dòng)化測(cè)試處理各種彈窗的操作方法
這篇文章主要介紹了Android自動(dòng)化測(cè)試中如何處理各種彈窗,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-07-07
Android編程簡(jiǎn)單設(shè)置ListView分割線的方法
這篇文章主要介紹了Android編程簡(jiǎn)單設(shè)置ListView分割線的方法,涉及Android布局簡(jiǎn)單操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02
flutter InkWell實(shí)現(xiàn)水波紋點(diǎn)擊效果
這篇文章主要為大家詳細(xì)介紹了flutter InkWell實(shí)現(xiàn)水波紋點(diǎn)擊效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
android之視頻播放系統(tǒng)VideoView和自定義VideoView控件的應(yīng)用
這篇文章主要介紹了android之視頻播放系統(tǒng)VideoView和自定義VideoView控件的應(yīng)用,需要的朋友可以參考下2017-03-03

