Flutter實現(xiàn)彈窗攔截器的示例代碼
前言
彈窗的排隊執(zhí)行在App中是一個很常見的應(yīng)用場景。比如進入App首頁,一系列的彈窗就會彈出。如果不做處理就會導(dǎo)致彈窗一窩蜂的全部彈出,嚴重影響用戶體驗。
如果多個彈窗中有判斷邏輯,同意協(xié)議彈出另一個彈窗,不同意彈窗另外一個彈窗,又添加了復(fù)雜度了。
所以才會有需要管理多個彈窗的展示時機,一般來說在一個Flutter App 中有下面幾種方式來管理的。
一、隊列的方式實現(xiàn)
其實最簡單最原始的方案就是硬寫,判斷邏輯寫在彈窗或Picker里面,一層一層的嵌套,反正布局都嵌套了,彈窗邏輯嵌套怕什么...
當(dāng)然比較好的做法是用一個隊列管理起來。
class DialogQueue { final Queue<AlertDialog> _dialogQueue = Queue(); bool _isShowingDialog = false; void show(AlertDialog dialog, BuildContext context) { _dialogQueue.add(dialog); if (!_isShowingDialog) { _isShowingDialog = true; _showNext(context); } } void _showNext(BuildContext context) { if (_dialogQueue.isNotEmpty) { final dialog = _dialogQueue.removeFirst(); showDialog<void>( context: context, builder: (BuildContext context) { return dialog; }, ).then((_) { if (_dialogQueue.isNotEmpty) { _showNext(context); } else { _isShowingDialog = false; } }); } } }
使用的時候,往隊列里面添加即可:
ElevatedButton( onPressed: () { _dialogQueue.show( AlertDialog( title: Text('Dialog 1'), content: Text('This is the first dialog'), ), context, ); }, child: Text('Show Dialog 1'), ), ElevatedButton( onPressed: () { _dialogQueue.show( AlertDialog( title: Text('Dialog 2'), content: Text('This is the second dialog'), ), context, ); }, child: Text('Show Dialog 2'), ),
代碼很簡單,但這樣雖然能做到排隊執(zhí)行,但是有幾個很大的問題,不夠靈活,不能控制其中哪一個不顯示或不顯示(實現(xiàn)起來比較麻煩),其次就是只支持 Dialog,不支持用 Toast SnackBar Picker等其他的用法。
總結(jié)一句話就是不夠靈活。那么我們之前使用過值攔截式的攔截器實現(xiàn)在 Android 平臺已經(jīng)實現(xiàn)過了。那么我們移植到 Flutter 平臺能不能實現(xiàn)對應(yīng)的功能呢?
二、攔截器的方式實現(xiàn)
與前文攔截器實現(xiàn)登錄攔截的方式有所區(qū)別的是通過值傳遞方式我們需要定義一個泛型,把傳遞的對象定義一下。
class InterceptChain<T> { InterceptChain? next; void intercept(T data) { next?.intercept(data); } }
管理類:
class InterceptChainHandler<T> { InterceptChain? _interceptFirst; void add(InterceptChain interceptChain) { if (_interceptFirst == null) { _interceptFirst = interceptChain; return; } InterceptChain? node = _interceptFirst; while (true) { if (node!.next == null) { node.next = interceptChain; break; } node = node.next; } } void intercept(T data) { _interceptFirst?.intercept(data); } }
與之前攔截登錄的方式不同的是,這種方案沒有指定的一些攔截器,更加的靈活,使用起來我們就需要定義每一個 InterceptChain ,也就是每一個 Dialog/Picker等效果都可以是一個 Intercept 。
class TipsIntercept extends InterceptChain<DialogPass> { @override void intercept(DialogPass data) { SmartDialog.show( usePenetrate: false, builder: (context) => AppDefaultDialog( "你確定要發(fā)送驗證碼嗎?", confirmAction: () { super.intercept(data); }, ), ); } } class VerifyIntercept extends InterceptChain<DialogPass> { @override void intercept(DialogPass data) { SmartDialog.show( usePenetrate: false, builder: (context) => VerifyCodeDialog( confirmAction: () { super.intercept(data); }, ), ); } } class OneIntercept extends InterceptChain<DialogPass> { @override void intercept(DialogPass data) { if (data != null) { final interceptData = '當(dāng)前的Data1:${data.msg}'; print(interceptData); if (data.passType == 1) { // 彈窗1 SmartDialog.show( usePenetrate: false, builder: (context) => AppDefaultDialog( data.msg ?? "", confirmAction: () { data.passType = 2; super.intercept(data); }, ), ); } else { super.intercept(data); } } else { super.intercept(data); } } } class TwoIntercept extends InterceptChain<DialogPass> { @override void intercept(DialogPass data) { if (data != null) { final interceptData = '當(dāng)前的Data2:${data.msg}'; print(interceptData); if (data.passType == 2) { // 彈窗2 SmartDialog.show( usePenetrate: false, clickMaskDismiss: false, builder: (context) => PrivacyPolicyDialog( confirmAction: () { data.passType = 3; super.intercept(data); }, cancelAction: () { super.intercept(data); }, ), ); } else { super.intercept(data); } } else { super.intercept(data); } } } class ThreeIntercept extends InterceptChain<DialogPass> { @override void intercept(DialogPass data) { if (data != null) { final interceptData = '當(dāng)前的Data3:${data.msg}'; print(interceptData); if (data.passType == 3) { // 彈窗2 DataPickerUtil.showCupertinoDataPicker( items: ["全部","等待確認", "已完成"], onPickerChanged: (list, position) { super.intercept(data); }, ); } else { super.intercept(data); } } else { super.intercept(data); } } }
這里簡單的定義了5個彈窗/Picker效果,并且簡單的定義了變量的控制對象為:
class DialogPass { String? msg; int passType = 0; DialogPass(this.msg, this.passType); }
這個是一般是由后臺服務(wù)器控制,請求接口之后可以動態(tài)的根據(jù)多個變量控制哪一個彈窗展示,并且可以控制一個彈窗展示之后它對應(yīng)的后續(xù)彈窗的展示。可以很方便的通過對象中的變量控制。
具體哪個彈窗是否展示,如何展示都是子 Intercept 控制,我們最終只需要把全部的攔截類添加到攔截器容器中即可:
final intercepts = InterceptChainHandler<DialogPass>(); intercepts.add(TipsIntercept()); intercepts.add(VerifyIntercept()); intercepts.add(OneIntercept()); intercepts.add(TwoIntercept()); intercepts.add(ThreeIntercept()); intercepts.intercept(DialogPass('你確定你要閱讀全部協(xié)議嗎1?',1));
效果:
雖然代碼是多一個但是相對而言就靈活一點。
后記
用隊列雖然也能實現(xiàn)一些特定的場景需求,但是我還是更推薦攔截器的方式,相對而言更靈活。
所以說一些在 iOS/Android 中成熟使用的一些設(shè)計模式真的是可以很方便的解決一些業(yè)務(wù)場景的痛點,并不限制于語言與平臺。
現(xiàn)在我們應(yīng)用中的首頁的彈窗與申請工作的彈窗校驗就能很方便的用攔截器的方式進行管理了。并且用值傳遞的方式我們也可以很方便的把最終處理過后的數(shù)據(jù)拿到可以進行其他的攔截或操作。
到此這篇關(guān)于Flutter實現(xiàn)彈窗攔截器的示例代碼的文章就介紹到這了,更多相關(guān)Flutter彈窗攔截器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android ViewPager實現(xiàn)Banner循環(huán)播放
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)Banner循環(huán)播放,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09Android編程之界面跳動提示動畫效果實現(xiàn)方法
這篇文章主要介紹了Android編程之界面跳動提示動畫效果實現(xiàn)方法,實例分析了Android動畫效果的布局及功能相關(guān)實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11Android基于OpenCV實現(xiàn)Harris角點檢測
角點就是極值點,即在某方面屬性特別突出的點。當(dāng)然,你可以自己定義角點的屬性(設(shè)置特定熵值進行角點檢測)。角點可以是兩條線的交叉處,也可以是位于相鄰的兩個主要方向不同的事物上的點。本文介紹如何基于OpenCV實現(xiàn)Harris角點檢測2021-06-06Android RxJava異步數(shù)據(jù)處理庫使用詳解
RxJava是一種異步數(shù)據(jù)處理庫,也是一種擴展的觀察者模式。對于Android開發(fā)者來說,使用RxJava時也會搭配RxAndroid,它是RxJava針對Android平臺的一個擴展,用于Android 開發(fā),它提供了響應(yīng)式擴展組件,使用RxAndroid的調(diào)度器可以解決Android多線程問題2022-11-11Android Studio中導(dǎo)入module的方法(簡單版)
這篇文章主要介紹了AndroidStudio中導(dǎo)入module的方法,本文是一篇簡易版的教程,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-01-01