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

如何在Flutter中实现与视频同款的SVG箭头动画?

实现三箭头SVG的逐次高亮动画方案

你当前用的shimmer是整体扫过的光效,但目标动画是三个箭头依次循环高亮,所以需要针对SVG内的箭头元素单独控制动画,而非给整个SVG加全局shimmer。以下是几种可行方案:

方案一:拆分SVG+flutter_animate逐次动画

步骤1:拆分SVG结构

打开你的down_arrows.svg,将三个箭头拆分为独立的元素(比如三个<path>),保存为单个箭头的SVG文件,或给每个箭头路径添加唯一id。

步骤2:Flutter代码实现

用Stack叠加默认状态的整体SVG和三个独立高亮箭头,分别添加延迟动画:

Stack(
  alignment: Alignment.center,
  children: [
    // 默认灰色箭头背景
    SvgPicture.asset(
      'assets/icons/down_arrows.svg',
      height: 32.h,
      width: 32.h,
      colorFilter: const ColorFilter.mode(
        AppColors.bottomNavIconGreen,
        BlendMode.srcIn,
      ),
    ),
    // 三个高亮箭头依次闪烁
    ...List.generate(3, (index) {
      return SvgPicture.asset(
        'assets/icons/single_down_arrow.svg', // 单个箭头的SVG文件
        height: 32.h,
        width: 32.h,
        colorFilter: const ColorFilter.mode(
          AppColors.mainGreen,
          BlendMode.srcIn,
        ),
      )
          .animate(
            onPlay: (controller) => controller.repeat(),
            delay: (index * 1000).ms, // 每个箭头延迟1秒启动循环
          )
          .fadeIn(duration: 500.ms)
          .fadeOut(duration: 500.ms);
    }),
  ],
)

方案二:SVG内置SMIL动画(无需Flutter代码控制)

直接在SVG文件中添加原生动画,flutter_svg支持SMIL动画:

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
  <!-- 顶部箭头 -->
  <path d="M16 8l-6 6h12l-6-6z" fill="#88c899">
    <animate attributeName="fill" values="#88c899;#2ecc71;#88c899" dur="3s" repeatCount="indefinite" begin="0s"/>
  </path>
  <!-- 中间箭头 -->
  <path d="M16 14l-6 6h12l-6-6z" fill="#88c899">
    <animate attributeName="fill" values="#88c899;#2ecc71;#88c899" dur="3s" repeatCount="indefinite" begin="1s"/>
  </path>
  <!-- 底部箭头 -->
  <path d="M16 20l-6 6h12l-6-6z" fill="#88c899">
    <animate attributeName="fill" values="#88c899;#2ecc71;#88c899" dur="3s" repeatCount="indefinite" begin="2s"/>
  </path>
</svg>

之后直接加载这个动画SVG即可:

SvgPicture.asset(
  'assets/icons/down_arrows_animated.svg',
  height: 32.h,
  width: 32.h,
)

方案三:AnimatedBuilder+ShaderMask控制单个SVG(不拆分)

如果不想拆分SVG,可通过着色器掩码根据动画值高亮对应区域:

class ArrowAnimation extends StatefulWidget {
  const ArrowAnimation({super.key});

  @override
  State<ArrowAnimation> createState() => _ArrowAnimationState();
}

class _ArrowAnimationState extends State<ArrowAnimation> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<int> _currentArrow;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(seconds: 3))..repeat();
    _currentArrow = StepTween(begin: 0, end: 2).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return ShaderMask(
          shaderCallback: (rect) {
            final gradient = LinearGradient(
              colors: [
                AppColors.bottomNavIconGreen,
                _currentArrow.value == 0 ? AppColors.mainGreen : AppColors.bottomNavIconGreen,
                _currentArrow.value == 1 ? AppColors.mainGreen : AppColors.bottomNavIconGreen,
                _currentArrow.value == 2 ? AppColors.mainGreen : AppColors.bottomNavIconGreen,
              ],
              stops: const [0, 0.33, 0.66, 1],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
            );
            return gradient.createShader(rect);
          },
          child: SvgPicture.asset(
            'assets/icons/down_arrows.svg',
            height: 32.h,
            width: 32.h,
          ),
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

推荐优先选择方案一或方案二,实现成本更低且动画效果精准。

内容的提问来源于stack exchange,提问作者Mehedi Hasan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:03:33