如何让CircularProgressIndicator运行流畅并添加边缘动态光晕效果
代码修改实现
首先需要给你的State类混入动画支持:
class YourTimerPageState extends State<YourTimerPage> with SingleTickerProviderStateMixin {
替换你原来的变量和相关方法即可:
final int maxSeconds = 900; late int seconds = maxSeconds; Timer? timer; // 新增:进度平滑动画控制器 late AnimationController _progressAnimController; // 新增:光晕缩放动画控制器 late AnimationController _glowAnimController; late Animation<double> _glowScaleAnim; @override void initState() { super.initState(); // 初始化进度动画控制器,时长和总计时时长一致 _progressAnimController = AnimationController( vsync: this, duration: Duration(seconds: maxSeconds), ); // 初始化光晕动画,2秒完成一次缩放循环,反向播放实现放大缩小往复 _glowAnimController = AnimationController( vsync: this, duration: const Duration(seconds: 2), )..repeat(reverse: true); _glowScaleAnim = Tween<double>(begin: 1.0, end: 1.1).animate( CurvedAnimation(parent: _glowAnimController, curve: Curves.easeInOut), ); } @override void dispose() { _progressAnimController.dispose(); _glowAnimController.dispose(); timer?.cancel(); super.dispose(); } void resetTimer() { setState(() => seconds = maxSeconds); _progressAnimController.reset(); timer = null; } void stopTimer({bool reset = true}) { timer?.cancel(); _progressAnimController.stop(); if (reset) { resetTimer(); } } void startTimer({bool reset = true}) { if (reset) { resetTimer(); } // 启动进度平滑动画 _progressAnimController.forward(from: seconds / maxSeconds); // 启动秒数更新定时器 timer = Timer.periodic(const Duration(seconds: 1), (_) { if (!mounted) return; if (seconds > 0) { setState(() => seconds--); } else { stopTimer(reset: false); } }); } Widget buildTimer() => SizedBox( width: 200, height: 200, child: Stack( fit: StackFit.expand, children: [ // 新增:光晕层 ScaleTransition( scale: _glowScaleAnim, child: Container( decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.white.withOpacity(0.6), blurRadius: 20, spreadRadius: 8, ), ], ), child: CircularProgressIndicator( value: _progressAnimController.value, valueColor: AlwaysStoppedAnimation(Colors.white.withOpacity(0.3)), strokeWidth: 12, backgroundColor: Colors.transparent, ), ), ), // 原有进度条 CircularProgressIndicator( value: _progressAnimController.value, valueColor: const AlwaysStoppedAnimation(Colors.white), strokeWidth: 12, backgroundColor: Colors.greenAccent, ), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { if (timer == null) { HapticFeedback.heavyImpact(); startTimer(reset: seconds == maxSeconds); } else { stopTimer(reset: false); } }, child: Center(child: buildTime()), ), ], ), );
效果说明
- 进度条通过动画控制器的插值计算实现60fps的流畅过渡,不会再出现每秒跳变的情况
- 光晕层绑定了循环缩放动画,会始终保持略微放大再缩小的呼吸效果,模糊半径和缩放比例可以自行调整
BoxShadow的参数和Tween的起止值适配需求
内容的提问来源于stack exchange,提问作者Bn Minki
相关产品推荐
相关产品推荐

