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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:24:56