You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中showDialog/Dialog无法更新倒计时/正计时问题求助

解决弹窗计时器不更新的问题

问题根源

当前弹窗仅在初始化时接收timer参数,后续外部timer变化无法触发弹窗UI重建,因为函数式组件没有状态监听机制。

方案一:将弹窗内容改为StatefulWidget

把弹窗里的内容改成带状态的组件,内部管理计时逻辑,自动触发UI更新:

void showFrostedGlassBox(BuildContext context) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return const Center(child: TestingTimer());
    },
  );
}

class TestingTimer extends StatefulWidget {
  const TestingTimer({super.key});

  @override
  State<TestingTimer> createState() => _TestingTimerState();
}

class _TestingTimerState extends State<TestingTimer> {
  late String _timerText;
  late Timer _countdownTimer;
  int _remainingSeconds = 60; // 示例倒计时时长

  @override
  void initState() {
    super.initState();
    _timerText = "$_remainingSeconds";
    _startCountdown();
  }

  void _startCountdown() {
    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (_remainingSeconds > 0) {
        setState(() {
          _remainingSeconds--;
          _timerText = "$_remainingSeconds";
        });
      } else {
        timer.cancel();
        // 计时结束后关闭弹窗
        Navigator.of(context).pop();
      }
    });
  }

  @override
  void dispose() {
    _countdownTimer.cancel(); // 销毁计时器,避免内存泄漏
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          width: 200,
          height: 200,
          decoration: BoxDecoration(
            // 自定义装饰样式
            color: Colors.white.withOpacity(0.8),
            borderRadius: BorderRadius.circular(16),
          ),
          child: Center(
            child: Text(
              _timerText,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ),
        ),
        // 关闭按钮
        Positioned(
          top: 8,
          right: 8,
          child: IconButton(
            icon: const Icon(Icons.close),
            onPressed: () {
              _countdownTimer.cancel();
              Navigator.of(context).pop();
            },
          ),
        ),
      ],
    );
  }
}

方案二:用ValueNotifier实现外部控制的响应式更新

如果需要从外部控制计时器变化,用ValueNotifier传递状态,弹窗通过ValueListenableBuilder监听更新:

// 定义状态容器,可放在父组件或全局(按需调整)
final ValueNotifier<String> timerNotifier = ValueNotifier("60");

void showFrostedGlassBox(BuildContext context) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return Center(child: TestingTimer());
    },
  );
}

Widget TestingTimer() {
  return ValueListenableBuilder<String>(
    valueListenable: timerNotifier,
    builder: (context, timerValue, child) {
      return Stack(
        children: [
          Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.8),
              borderRadius: BorderRadius.circular(16),
            ),
            child: Center(
              child: Text(
                timerValue,
                style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
            ),
          ),
          Positioned(
            top: 8,
            right: 8,
            child: IconButton(
              icon: const Icon(Icons.close),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ),
        ],
      );
    },
  );
}

// 外部触发计时的示例方法
void startExternalCountdown() {
  int seconds = 60;
  Timer.periodic(const Duration(seconds: 1), (timer) {
    if (seconds > 0) {
      seconds--;
      timerNotifier.value = "$seconds";
    } else {
      timer.cancel();
    }
  });
}

关键提示

  • 方案一适合弹窗独立管理计时逻辑的场景,无需外部干预。
  • 方案二适合需要外部控制计时状态的场景,通过状态容器传递变化。
  • 两种方案都要在弹窗关闭时销毁计时器,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Sulaiman Fazli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 16:12:40