背景
??在項(xiàng)目開發(fā)中經(jīng)常會(huì)碰到有時(shí)要根據(jù)業(yè)務(wù)后臺(tái)接口顯示一些提示框或者引導(dǎo)框什么的,有時(shí)這些彈框要多次顯示或只顯示一次,并且它們內(nèi)部也有一定的優(yōu)先級(jí),還要保證一個(gè)一個(gè)的顯示率触,不能重疊。還有一些操作完成后汇竭,進(jìn)入到了指定的頁面才顯示這個(gè)操作之后的提示或引導(dǎo)彈窗葱蝗。特別是在 Flutter 中痊剖,這些還顯示更為復(fù)雜,因?yàn)樵膹棿暗膬?yōu)先級(jí)比 Flutter 的優(yōu)先級(jí)高垒玲,例如權(quán)限申請(qǐng)陆馁、指紋等。
??這就使得處理更為復(fù)雜合愈,通用的處理是在界面通些一些變量來控制當(dāng)前是否有彈窗在顯示叮贩,來判斷其它的彈窗要不要顯示,或者通過標(biāo)識(shí)來確認(rèn)彈窗是否已經(jīng)顯示過佛析;這就使得界面上有各種各樣的臨時(shí)變更益老,及各種判斷,這樣就非常影響整個(gè)界面的可讀性寸莫。
??所以在這里就把項(xiàng)目中一些處理的思路與方法跟大家分享下捺萌,大家一起學(xué)習(xí)。
現(xiàn)狀
- 彈窗樣式多樣膘茎、多個(gè)彈窗重疊桃纯、多個(gè)彈窗間有優(yōu)先級(jí)
- 有時(shí)彈窗需指定特定頁面
- 同一彈窗會(huì)重復(fù)顯示
- 彈窗無法指定關(guān)閉
思路
- 對(duì)于上述場景,對(duì)于自動(dòng)觸發(fā)彈出的彈窗披坏,統(tǒng)一加到彈窗管理中态坦。
- 對(duì)于沒有指定頁面的彈窗,則加入到頂層頁面中棒拂。彈窗管理有特定頂層頁面伞梯,用于顯示當(dāng)前頂層需顯示的彈窗列表
- 對(duì)于需要在特定頁面顯示的彈窗,則在需要顯示前判斷當(dāng)前頂層視圖是否為特定頁面(因?yàn)?Flutter 中彈窗無需與頁面關(guān)聯(lián))帚屉。
- 每個(gè)彈窗都有優(yōu)先級(jí)谜诫,在頁面需要顯示前,會(huì)先進(jìn)行優(yōu)先級(jí)排序攻旦,再根據(jù)排序結(jié)果進(jìn)行展示
- 每個(gè)彈窗都會(huì)生成一個(gè)固定的唯一標(biāo)識(shí)喻旷,用于處理彈窗重復(fù)問題
- 對(duì)于彈窗無法指定關(guān)閉的問題,如有需強(qiáng)制顯示的彈窗敬特,則會(huì)先判斷當(dāng)前是否有顯示的彈窗掰邢,有則先 pop彈窗再顯示強(qiáng)制的彈窗
實(shí)現(xiàn)效果
解決辦法
DialogManager
統(tǒng)一彈窗管理類,管理彈窗的添加及顯示伟阔,詳細(xì)代碼見最后。
- 初始化方法
??初始化方法中生成兩個(gè)數(shù)組List<DialogBean> _dialogList掰伸,_hasShowBeans皱炉。_dialogList用于儲(chǔ)存加入在統(tǒng)一彈窗中的彈窗數(shù)據(jù)
_hasShowBeans用于存儲(chǔ)已經(jīng)顯示過,還沒有清除的彈窗數(shù)據(jù)
??為什么不用單一 bean 去儲(chǔ)存顯示的彈窗數(shù)據(jù)狮鸭,因?yàn)橹脼榭盏奶幚砗辖粒窃趶棿跋У漠惒交卣{(diào)中多搀,如果一個(gè)新的彈窗要顯示,舊的那個(gè)彈窗消失的回調(diào)過來會(huì)把當(dāng)前在顯示的彈窗數(shù)據(jù)置為空灾部,則會(huì)導(dǎo)致當(dāng)前判斷時(shí)否有顯示的彈窗不準(zhǔn)確康铭。
- add 方法
主要用于添加彈窗數(shù)據(jù)在_dialogList中
- 假如添加的彈窗為 highClear 或 highClearAll,則會(huì)移除其它低優(yōu)先級(jí)的彈窗赌髓。主要場景是在強(qiáng)制升級(jí)彈窗从藤、多終端登錄彈窗
- 對(duì)于重復(fù)添加的彈窗,則不重復(fù)添加
- 對(duì)于棧中已經(jīng)存在 highClear 或 highClearAll級(jí)別彈窗锁蠕,則不添加低優(yōu)先級(jí)彈窗
- 對(duì)所有的彈窗進(jìn)行優(yōu)先級(jí)排序
- show 方法
主要用于添加彈窗數(shù)據(jù)在_dialogList中
- 假如添加的彈窗為 highClear 或 highClearAll夷野,則會(huì)移除其它低優(yōu)先級(jí)的彈窗。主要場景是在強(qiáng)制升級(jí)彈窗荣倾、多終端登錄彈窗
- 對(duì)于重復(fù)添加的彈窗悯搔,則不重復(fù)添加
- 對(duì)于棧中已經(jīng)存在 highClear 或 highClearAll級(jí)別彈窗,則不添加低優(yōu)先級(jí)彈窗
- 對(duì)所有的彈窗進(jìn)行優(yōu)先級(jí)排序
DialogBean
///dialog唯一標(biāo)識(shí)舌仍,通過 DialogBean 數(shù)據(jù)內(nèi)容生成 Md5生成
String dialogId;
///當(dāng)前 dialog妒貌,顯示的視圖。如果為空铸豁,則在頂層頁面
String pageRouter;
///優(yōu)先級(jí)苏揣、用于顯示彈窗前排序,
///但對(duì)于加入的彈窗推姻,已經(jīng)顯示的情況
///[highClear] 清除已顯示的彈窗平匈,直接顯示當(dāng)前彈窗,該屬性慎用
///[high] 回收當(dāng)前已顯示的彈窗藏古,再顯示高優(yōu)先級(jí)彈窗增炭,該屬性慎用
DialogPriority dialogPriority;
///用于排序
int priority;
///彈窗內(nèi)部業(yè)務(wù) widget,每次show 時(shí)動(dòng)態(tài)創(chuàng)建。不能直接傳創(chuàng)建好的 widget拧晕,因?yàn)樵?high回收時(shí)隙姿,調(diào)用 pop 再 show 會(huì)出現(xiàn) The following NoSuchMethodError was thrown building Builder(dirty):
CreateDialogWidget createDialogWidg
統(tǒng)一的彈窗實(shí)體類,詳細(xì)代碼見最后厂捞。
- dialogId,用于彈窗去重
- pageRouter用于指定彈窗需顯示的頁面输玷,如果沒有指定,則直接顯示
- dialogPriority標(biāo)識(shí)彈窗優(yōu)先級(jí)
- priority彈窗優(yōu)先級(jí)擴(kuò)展字段靡馁,主要用于排序
- createDialogWidget生成彈窗widget.不用直接使用 widget欲鹏,在 high 回收時(shí),再顯示會(huì)報(bào)異常臭墨。
DialogUtil
公共彈窗創(chuàng)建類赔嚎,詳細(xì)代碼見最后。
- 生成對(duì)應(yīng) dialog 唯一的 id
- dialog 業(yè)務(wù)自身內(nèi)部處理
- 需要加入統(tǒng)一彈窗管理中 dialog 統(tǒng)一在這里生成
場景驗(yàn)證
多個(gè)彈窗是否按順序依次彈出
DialogManager()
..add(
DialogBean(
dialogPriority: DialogPriority.high,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗\n 換行
"),
))
..add(
DialogBean(
dialogPriority: DialogPriority.high,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗"),
))
..show(context);
相同的彈窗是否去重
DialogManager()
..add(
DialogBean(
dialogPriority: DialogPriority.high,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗"),
))
..add(
DialogBean(
dialogPriority: DialogPriority.high,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗"),
))
..show(context);
彈窗回收:已彈出低優(yōu)先級(jí)彈窗,顯示高優(yōu)先級(jí)彈窗尤误,是否可以回收顯示
DialogManager()
..add(
DialogBean(
createDialogWidget: () => DialogUtil.createTipWidget(
context,
"測試彈窗\n 換行",
),
))
..show(context);
Future.delayed(Duration(seconds: 1), () {
DialogManager()
..add(
DialogBean(
dialogPriority: DialogPriority.high,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗"),
))
..show(context);
});
可反過來,先顯示高優(yōu)先級(jí)侠畔,再顯示其它
彈窗清除:已彈出低優(yōu)先級(jí)彈窗,顯示高優(yōu)先級(jí)并清除其它的彈窗
DialogManager()
..add(
DialogBean(
createDialogWidget: () => DialogUtil.createTipWidget(
context,
"測試彈窗\n 換行"
),
))
..show(context);
Future.delayed(Duration(seconds: 1), () {
DialogManager()
..add(
DialogBean(
dialogPriority: DialogPriority.highClear,
createDialogWidget: () =>
DialogUtil.createTipWidget(context, "測試彈窗"),
))
..show(context);
});
彈窗頁面驗(yàn)證:指定彈窗在指定頁面顯示
Future.delayed(Duration(seconds: 1), () {
DialogManager()
..add(
DialogBean(
pageRouter: Router.login,
createDialogWidget: () => DialogUtil.createTipWidget(
context,
"測試彈窗",
),
))
..show(context);
});
最后
??如果在使用過程遇到問題损晤,歡迎下方留言交流软棺。
??代碼下載地址