show static method

void show(
  1. BuildContext context, {
  2. required PlayStatus widgetStatus,
  3. String? statusMessage,
  4. String? statusCode,
  5. 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();
      }
    });
  }
}