使用flutter_animate实现弹性缩放脉冲动画的问题求助
flutter_animate实现弹性脉冲缩放动画的问题解决方案
问题1:从scale=1.0开始并回归1.0但无法触发动画
flutter_animate默认不会触发起始/结束值相同的动画,且重复触发需要强制重置动画状态。解决方案:
- 用
ValueKey绑定ValueNotifier的当前值,每次数值变更时重建Animate组件,确保动画从头开始执行 - 将脉冲拆分为两个连续的scale动画:先从1.0放大到峰值,再从峰值缩小回1.0,保证整体起始和结束状态都是scale=1.0
问题2:数值变更到动画启动存在延迟
延迟通常来自动画自动触发的逻辑或状态更新的异步延迟,解决方案:
- 在Animate的
onPlay回调中手动调用controller.reset().forward(),强制动画立即重置并播放,避免自动触发的滞后 - 确保ValueNotifier/ChangeNotifier的
notifyListeners()是同步调用的,不要放在异步任务中执行
问题3:Curves.elasticInOut弹性弹跳效果不足
默认弹性曲线的振幅和周期固定,可通过自定义曲线增强效果:
- 实现自定义
ElasticCurve类,调整振幅(amplitude)和周期(period)参数,获得更强烈的弹跳感 - 将自定义曲线传入scale动画的
curve参数,替代默认的Curves.elasticInOut
完整示例代码
import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'dart:math'; class WPulse extends StatelessWidget { final ValueNotifier<int> pulseNotifier; final Widget child; final double scalePeak; final Duration duration; final Curve curve; const WPulse({ super.key, required this.pulseNotifier, required this.child, this.scalePeak = 1.5, this.duration = const Duration(milliseconds: 800), this.curve = const ElasticCurve(amplitude: 1.2, period: 0.4), }); @override Widget build(BuildContext context) { return ValueListenableBuilder<int>( valueListenable: pulseNotifier, builder: (context, value, child) { return child! .animate( key: ValueKey(value), onPlay: (controller) => controller.reset().forward(), ) .scale( begin: 1.0, end: scalePeak, duration: duration ~/ 2, curve: curve, ) .scale( begin: scalePeak, end: 1.0, duration: duration ~/ 2, curve: curve.flipped, ); }, child: child, ); } } // 自定义弹性曲线,可调整振幅和周期增强弹跳效果 class ElasticCurve extends Curve { final double amplitude; final double period; const ElasticCurve({this.amplitude = 1.0, this.period = 0.3}); @override double transform(double t) { return 1 - pow(2, -10 * t) * sin((t - period / 4) * (2 * pi) / period) * amplitude; } } // 使用示例 class PulseDemo extends StatefulWidget { const PulseDemo({super.key}); @override State<PulseDemo> createState() => _PulseDemoState(); } class _PulseDemoState extends State<PulseDemo> { final ValueNotifier<int> _pulseCount = ValueNotifier(0); void _triggerPulse() { _pulseCount.value += 1; } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: WPulse( pulseNotifier: _pulseCount, child: Container( width: 80, height: 80, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(40), ), child: const Center(child: Text("Badge", style: TextStyle(color: Colors.white))), ), ), ), floatingActionButton: FloatingActionButton( onPressed: _triggerPulse, child: const Icon(Icons.add), ), ); } }
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

