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

Flutter Riverpod:将倒计时控制器参数移至类内函数

解决方案:重构CountdownController实现便捷启停

核心思路

把初始时长从构造参数移到startTimer方法中,同时在控制器内部维护剩余时长和运行状态,这样启停时无需重复传入时长,直接基于当前状态操作即可。下面是基于Riverpod 3.x(使用Notifier)的完整实现:

1. 定义倒计时状态类

先创建一个类封装倒计时的核心状态,方便统一管理:

class CountdownState {
  const CountdownState({
    required this.remainingSeconds,
    required this.isRunning,
  });

  // 剩余秒数,为0时表示倒计时结束
  final int remainingSeconds;
  // 是否正在运行
  final bool isRunning;

  // 生成新状态的方法,避免直接修改原状态
  CountdownState copyWith({
    int? remainingSeconds,
    bool? isRunning,
  }) {
    return CountdownState(
      remainingSeconds: remainingSeconds ?? this.remainingSeconds,
      isRunning: isRunning ?? this.isRunning,
    );
  }

  // 初始状态:未启动,剩余时长0
  static const initial = CountdownState(remainingSeconds: 0, isRunning: false);
}

2. 实现CountdownNotifier

使用Riverpod的Notifier来实现倒计时的业务逻辑,把时长参数移到startTimer方法:

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:async';

class CountdownNotifier extends Notifier<CountdownState> {
  Timer? _timer;

  @override
  CountdownState build() {
    return CountdownState.initial;
  }

  // 启动倒计时,传入初始时长(秒)
  void startTimer(int initialDuration) {
    // 先停止已有定时器
    _timer?.cancel();
    // 更新状态:设置初始时长,标记为运行中
    state = state.copyWith(
      remainingSeconds: initialDuration,
      isRunning: true,
    );
    // 启动定时器,每秒更新剩余时长
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (state.remainingSeconds <= 1) {
        // 倒计时结束,停止定时器并更新状态
        timer.cancel();
        state = state.copyWith(
          remainingSeconds: 0,
          isRunning: false,
        );
      } else {
        // 每秒减1
        state = state.copyWith(
          remainingSeconds: state.remainingSeconds - 1,
        );
      }
    });
  }

  // 暂停倒计时
  void pauseTimer() {
    _timer?.cancel();
    state = state.copyWith(isRunning: false);
  }

  // 恢复倒计时(基于当前剩余时长继续)
  void resumeTimer() {
    if (state.remainingSeconds <= 0) return; // 已结束则不恢复
    _timer?.cancel();
    state = state.copyWith(isRunning: true);
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (state.remainingSeconds <= 1) {
        timer.cancel();
        state = state.copyWith(
          remainingSeconds: 0,
          isRunning: false,
        );
      } else {
        state = state.copyWith(
          remainingSeconds: state.remainingSeconds - 1,
        );
      }
    });
  }

  // 重置倒计时(回到未启动状态)
  void resetTimer() {
    _timer?.cancel();
    state = CountdownState.initial;
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }
}

// 定义Riverpod Provider
final countdownProvider = NotifierProvider<CountdownNotifier, CountdownState>(
  CountdownNotifier.new,
);

3. UI层使用示例

在任意页面中通过Provider获取控制器,实现跨页面同步:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CountdownPage extends ConsumerWidget {
  const CountdownPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final countdownState = ref.watch(countdownProvider);
    final countdownNotifier = ref.read(countdownProvider.notifier);

    return Scaffold(
      appBar: AppBar(title: const Text("跨页面倒计时")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 显示剩余时间
            Text(
              "${countdownState.remainingSeconds}s",
              style: const TextStyle(fontSize: 48),
            ),
            const SizedBox(height: 20),
            // 操作按钮组
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (!countdownState.isRunning && countdownState.remainingSeconds > 0)
                  ElevatedButton(
                    onPressed: countdownNotifier.resumeTimer,
                    child: const Text("继续"),
                  ),
                if (countdownState.isRunning)
                  ElevatedButton(
                    onPressed: countdownNotifier.pauseTimer,
                    child: const Text("暂停"),
                  ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () => countdownNotifier.startTimer(60), // 传入初始时长60秒
                  child: const Text("启动60秒倒计时"),
                ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: countdownNotifier.resetTimer,
                  child: const Text("重置"),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

关键改进点

  • 时长参数内移:不再在构造时传入时长,而是通过startTimer(int duration)方法动态设置,启动时按需传入即可。
  • 状态持久化:控制器内部维护剩余时长和运行状态,暂停/恢复时直接基于当前状态操作,无需重复传入参数。
  • 跨页面同步:通过Riverpod的Provider,任意页面监听countdownProvider都能获取实时状态,实现跨页面同步显示和操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:37:45