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