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
相关产品推荐
相关产品推荐

