Flutter如何让旋转动画更流畅?解决5秒刷新生硬重启问题
解决Flutter旋转动画生硬重启并实现反向播放的方案
问题根源
你的代码里直接修改change_rotation_speed参数,会导致Transform.rotate的angle值突然跳变,出现生硬的重启效果;同时没有保留当前旋转的累计角度,没法基于现有状态平滑过渡方向。
解决方案
核心思路是维护实际旋转的累计角度,每次切换时基于当前角度平滑过渡方向和速度,避免突变。以下是修改后的完整代码:
import 'dart:async'; import 'dart:math' as math; import 'package:flutter/material.dart'; import 'dart:math'; class SpinnerAnimation extends StatefulWidget { final Widget body; SpinnerAnimation({required this.body}); @override _SpinnerAnimationState createState() => _SpinnerAnimationState(); } class _SpinnerAnimationState extends State<SpinnerAnimation> with SingleTickerProviderStateMixin { late AnimationController _controller; // 记录旋转以来的总角度(弧度) double _totalRotation = 0.0; // 旋转方向:1正向,-1反向 int _rotationDirection = 1; // 当前旋转速度系数 double _speed = 1.2; late Timer _timer; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 10), vsync: this, ); // 监听动画帧,实时累计旋转角度 _controller.addListener(() { final frameRotation = _controller.value * _speed * math.pi * 2 * _rotationDirection; _totalRotation = frameRotation; }); // 启动初始动画 _controller.repeat(); // 每5秒切换方向和速度 _timer = Timer.periodic(const Duration(seconds: 5), (_) { _switchRotation(); }); } void _switchRotation() { setState(() { // 反转旋转方向 _rotationDirection *= -1; // 生成新的随机速度 _speed = randoDoubleGeneratorWithRange(1.2, 5); }); // 基于当前累计角度,计算反向动画的目标值 final targetValue = (_totalRotation / (_speed * math.pi * 2 * _rotationDirection)).clamp(0.0, 1.0); // 平滑过渡到目标状态后继续循环 _controller.animateTo(targetValue, duration: const Duration(milliseconds: 300)).then((_) { _controller.repeat(); }); } @override void dispose() { _controller.dispose(); _timer.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, child: widget.body, builder: (BuildContext context, Widget? child) { final currentAngle = _controller.value * _speed * math.pi * 2 * _rotationDirection; return Transform.rotate( angle: currentAngle, child: child, ); }, ); } double randoDoubleGeneratorWithRange(double min, double max) { return min + Random().nextDouble() * (max - min); } }
关键改动说明
- 累计角度维护:通过
_totalRotation记录当前实际旋转的角度,避免切换时角度重置 - 平滑过渡:使用
animateTo方法,用300ms的过渡时间切换到反向状态,完全消除生硬跳转 - 方向控制:通过
_rotationDirection的正负值控制旋转方向,切换时直接取反即可 - 定时器管理:在
dispose中取消定时器,避免内存泄漏
可选调整
- 如果不需要每次切换都改变速度,删掉
_speed的随机生成逻辑即可 - 调整
animateTo的duration参数,可以改变过渡的快慢(比如改成500ms会更平缓)
内容的提问来源于stack exchange,提问作者Petro
相关产品推荐
相关产品推荐

