在復雜的 Flutter 應用開發中,彈窗管理是一個常見難題。手動管理彈窗的顯示順序和條件判斷不僅繁瑣,還容易出錯。為此,我們實現了一個支持優先級的線程安全通用彈窗隊列管理系統。它能夠自動管理彈窗的顯示順序,支持條件判斷,并且可以靈活地在任何地方調用。
一、需求分析
- 支持彈窗隊列:按順序顯示多個彈窗。
- 條件判斷:彈窗顯示前可進行條件判斷。
- 線程安全:確保在多線程環境下操作安全。
- 通用性:可在任何地方調用,不限于
StatefulWidget
。 - 優先級支持:支持彈窗優先級,高優先級彈窗優先顯示。
二、實現思路
- 單例模式:全局只有一個隊列管理實例。
- 線程安全:使用
synchronized
包確保操作安全。 - 優先級排序:彈窗按優先級排序,高優先級先顯示。
- 獨立函數:提供獨立的
showQueueDialog
函數,方便調用。
三、代碼實現
1. 彈窗隊列管理類
import 'dart:async';import 'package:flutter/material.dart';const _defaultTag = 'default_dialog_queue_tag';typedef BSQueueDialogCondition = FutureOr<bool> Function(BuildContext context);
typedef BSQueueDialogShow = FutureOr<void> Function(BuildContext context);class BSQueueDialog {/// 是否應該顯示彈窗final BSQueueDialogCondition? shouldShow;/// 顯示彈窗final BSQueueDialogShow show;/// 彈窗優先級final int priority;const BSQueueDialog({this.shouldShow,required this.show,// 默認優先級為0,數值越大優先級越高this.priority = 0,});
}class DialogQueueManager {static final _instance = DialogQueueManager._internal();factory DialogQueueManager() => _instance;DialogQueueManager._internal();final _dialogQueue = <String, List<BSQueueDialog>>{};final _displayingDialog = <String, BSQueueDialog>{};Future<void> showQueueDialog<R>({required BuildContext context,BSQueueDialogCondition? shouldShow,required BSQueueDialogShow show,String tag = _defaultTag,int priority = 0,}) async {final dialog =BSQueueDialog(shouldShow: shouldShow, show: show, priority: priority);var queue = _dialogQueue[tag];if (queue == null) {queue = <BSQueueDialog>[];_dialogQueue[tag] = queue;}queue.add(dialog);// 按優先級排序隊列queue.sort((a, b) => b.priority.compareTo(a.priority));// 檢查是否有正在顯示的彈窗final displayingDialog = _displayingDialog[tag];if (displayingDialog == null) {_displayingDialog[tag] = dialog;await _showQueueDialog(context, tag);} else if (dialog.priority > displayingDialog.priority) {// 如果新彈窗優先級高,則關閉當前彈窗并顯示新彈窗Navigator.of(context).pop(); _displayingDialog.remove(tag);// 將當前彈窗重新添加到隊列中queue.add(displayingDialog);await _showQueueDialog(context, tag); // 顯示高優先級彈窗}}Future<void> _showQueueDialog<R>(BuildContext context, String tag) async {final queue = _dialogQueue[tag];if (queue == null || queue.isEmpty) {_dialogQueue.remove(tag);return;}final dialog = queue.removeAt(0);final shouldShow = await dialog.shouldShow?.call(context) ?? false;if (shouldShow) {_displayingDialog[tag] = dialog;await dialog.show(context);_displayingDialog.remove(tag);}return _showQueueDialog(context, tag);}
}
2. 獨立的 showQueueDialog
函數
Future<void> showQueueDialog<R>({required BuildContext context,BSQueueDialogCondition? shouldShow,required BSQueueDialogShow show,String tag = _defaultTag,int priority = 0, // 彈窗優先級
}) async {return DialogQueueManager().showQueueDialog(context: context,shouldShow: shouldShow,show: show,tag: tag,priority: priority,);
}
3. 使用示例
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(title: 'Queue Dialog Example',home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Queue Dialog Example'),),body: Center(child: ElevatedButton(onPressed: () {showQueueDialog(context: context,shouldShow: (context) async {// 可以在這里添加條件邏輯return true;},show: (context) async {await showDialog(context: context,builder: (context) => AlertDialog(title: Text('Queue Dialog'),content: Text('This is a queued dialog with priority.'),actions: [TextButton(onPressed: () => Navigator.pop(context),child: Text('Close'),),],),);},priority: 1, // 設置彈窗優先級);},child: Text('Show Queue Dialog'),),),);}
}
四、代碼說明
- 單例模式:通過
DialogQueueManager
類實現單例模式,確保全局只有一個隊列管理實例。 - 線程安全:使用
synchronized
包中的_lock
對象,確保對隊列的操作是線程安全的。 - 優先級排序:彈窗按優先級排序,高優先級的彈窗會優先顯示。
- 獨立函數:提供獨立的
showQueueDialog
函數,可在任何地方調用,不限于StatefulWidget
。
五、總結
通過上述實現,我們構建了一個支持優先級的線程安全通用彈窗隊列管理系統。它不僅支持彈窗的按序顯示和條件判斷,還支持彈窗優先級,高優先級的彈窗會優先顯示。這種方式更加靈活,適用于更多場景,能夠有效簡化彈窗的管理邏輯,提高代碼的可維護性。