在复杂的 Flutter 应用开发中,弹窗管理是一个常见难题。手动管理弹窗的显示顺序和条件判断不仅繁琐,还容易出错。为此,我们实现了一个支持优先级的线程安全通用弹窗队列管理系统。它能够自动管理弹窗的显示顺序,支持条件判断,并且可以灵活地在任何地方调用。
一、需求分析
- 支持弹窗队列:按顺序显示多个弹窗。
- 条件判断:弹窗显示前可进行条件判断。
- 线程安全:确保在多线程环境下操作安全。
- 通用性 :可在任何地方调用,不限于
StatefulWidget
。 - 优先级支持:支持弹窗优先级,高优先级弹窗优先显示。
二、实现思路
- 单例模式:全局只有一个队列管理实例。
- 线程安全 :使用
synchronized
包确保操作安全。 - 优先级排序:弹窗按优先级排序,高优先级先显示。
- 独立函数 :提供独立的
showQueueDialog
函数,方便调用。
三、代码实现
1. 弹窗队列管理类
dart
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
函数
dart
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. 使用示例
dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Queue Dialog Example',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
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
。
五、总结
通过上述实现,我们构建了一个支持优先级的线程安全通用弹窗队列管理系统。它不仅支持弹窗的按序显示和条件判断,还支持弹窗优先级,高优先级的弹窗会优先显示。这种方式更加灵活,适用于更多场景,能够有效简化弹窗的管理逻辑,提高代码的可维护性。