show static method
void
show(
- BuildContext context, {
- required PlayStatus widgetStatus,
- String? statusMessage,
- String? statusCode,
- Duration? duration = const Duration(seconds: 2),
显示播放状态
duration:
- 对于 Loading 状态:如果为 null,则不自动消失,需手动调用 hide()。
- 对于其他状态:默认为 2秒,必须在指定时间后消失。
Implementation
static void show(
BuildContext context, {
required PlayStatus widgetStatus,
String? statusMessage,
String? statusCode,
Duration? duration = const Duration(seconds: 2),
}) {
// 1. 基础安全检查
if (!context.mounted) return;
// 2. 移除旧的 Overlay 和取消旧的 Timer
// 这一步至关重要,确保同一时间只有一个提示,并清除之前的自动隐藏计划
_cancelAutoHideTimer();
_removeCurrentEntry();
// 3. 再次检查 Context,防止在 remove 过程中页面被销毁
if (!context.mounted) return;
// 4. 创建新的 OverlayEntry
final newEntry = OverlayEntry(
builder: (overlayContext) {
return _PlayStateOverlayContent(
widgetStatus: widgetStatus,
statusCode: statusCode,
statusMessage: statusMessage,
);
},
);
// 5. 插入 Overlay
try {
final overlayState = Overlay.of(context, rootOverlay: true);
// 确保 OverlayState 本身是有效的
if (overlayState.context.mounted) {
overlayState.insert(newEntry);
} else {
return; // Overlay 不可用,直接放弃
}
} catch (e) {
debugPrint("PlayStateShowUtil: Overlay insert failed: $e");
return;
}
// 6. 更新全局引用
_currentEntry = newEntry;
// 7. 设置自动隐藏逻辑
// 逻辑:如果是 Loading 且 duration 为 null,则不设置定时器(长期显示)
// 其他情况,或者 Loading 指定了 duration,则设置定时器
if (duration != null && duration > Duration.zero) {
_autoHideTimer = Timer(duration, () {
// 【关键修复】:这里不再检查 context.mounted!
// 即使页面销毁了,如果 Entry 还在屏幕上,我们必须把它移除,否则就是内存泄漏/UI残留。
// 我们只检查这个 Timer 是否对应当前的 Entry,防止旧 Timer 误删新 Entry。
if (_currentEntry == newEntry) {
_removeCurrentEntry();
}
});
}
}