背景:
在使用GetX框架时,同时使用了Get.snackbar提示框和Get.dialog加载框,当这两个widget同时存在时,Get.dialog加载框调用Get.back()无法正常关闭。
冲突解释:
之所以会产生冲突,是因为Get.snackbar在关闭时会有一个动画,这个动画的默认持续时间为1s,这个动画的持续时间内,Get.snackbar并没有真正意义上的关闭,这时候我们调用Get.back()是无法关闭Get.dialog。
实现:
- 创建一个统一的SnackBarManager去管理提示框。
import 'package:get/get.dart';
import 'package:flutter/material.dart';
class SnackBarManager {
factory SnackBarManager() => instance;
static final SnackBarManager instance = SnackBarManager._internal();
SnackBarManager._internal();
String _lastMessage = '';
int _lastDuration = 0;
int _lastTime = 0;
void showSnackBar(String title, String message, {Color? backgroundColor, Duration? duration}) {
var currentTime = DateTime.now().millisecondsSinceEpoch;
// 相同消息持续时间内重复提交时,返回
if (currentTime - _lastTime < _lastDuration * 1000 && _lastMessage == message) {
return;
}
dismissSnackBar();
Get.snackbar(
title,
message,
backgroundColor: backgroundColor ?? Colors.black12,
duration: duration ?? Duration(seconds: 2), // 提示框持续时间
animationDuration: Duration(milliseconds: 0), // 过渡动画的时间,这里设置为0是为了在使用Get.dialog时避免关闭冲突
);
_lastDuration = duration?.inSeconds ?? 2;
_lastTime = DateTime.now().millisecondsSinceEpoch;
_lastMessage = message;
}
void dismissSnackBar() {
Get.closeCurrentSnackbar();
}
}
这是一个避免重复显示的显示的提示框,可参考博客:Flutter中Get.snackbar避免重复显示的实现
2. 创建一个LoadingDialog去实现加载框。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
class LoadingDialog {
static void show([String? msg]) {
Get.dialog(
PopScope(
canPop: false,
child: Center(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16), // 减小内边距
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min, // 设置为最小宽度
children: [
SizedBox(
width: 24, // 减小加载图标尺寸
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2.0, // 可以适当减小进度条宽度
),
),
SizedBox(width: 12), // 减小间距
Text(
msg ?? "加载中...",
style: TextStyle(fontSize: 14, color: Colors.black), // 可以适当调整字体大小
),
],
),
),
),
),
barrierDismissible: false,
);
}
static void hide() {
if (Get.isDialogOpen ?? false) {
// 先关闭 Snackbar
Get.closeCurrentSnackbar();
// 添加延迟以确保 Snackbar 已关闭
Future.delayed(Duration(milliseconds: 100), () {
if (Get.isDialogOpen ?? false) {
Get.back();
}
});
}
}
}
在关闭加载框之前,会先关闭提示框,由于Get.snackbar动画时长已经设置为0,此时延迟100ms后再关闭加载框是没有问题的。