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

如何链式调用SlideTransition实现多阶段滑动动画?

实现多阶段动画方案

你可以通过监听动画状态结合Future.delayed,或者使用TweenSequence组合动画段,来完成这三个阶段的动画逻辑。以下是两种可行方案:


方案一:使用TweenSequence组合完整动画序列

这种方式将所有动画阶段整合到一个控制器中,逻辑更简洁,适合固定时长的场景:

class YourWidget extends StatefulWidget {
  final Duration duration;
  const YourWidget({super.key, required this.duration});

  @override
  State<YourWidget> createState() => _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> with SingleTickerProviderStateMixin {
  late AnimationController animationController;
  late Animation<Offset> slideAnimation;
  late Animation<double> opacityAnimation;

  @override
  void initState() {
    super.initState();
    // 总时长 = 第一段移动时长 + 等待时长 + 第二段移动消失时长
    final totalDuration = widget.duration + const Duration(seconds: 2) + const Duration(seconds: 1);
    animationController = AnimationController(duration: totalDuration, vsync: this);

    // 位移动画序列:位置1→位置2 → 保持位置2 → 位置2→位置3
    slideAnimation = TweenSequence([
      TweenSequenceItem(
        tween: Tween<Offset>(begin: const Offset(1.0, 0), end: const Offset(0.0, 0)),
        weight: widget.duration.inMilliseconds.toDouble(),
      ),
      TweenSequenceItem(
        tween: ConstantTween<Offset>(const Offset(0.0, 0)),
        weight: 2000.0,
      ),
      TweenSequenceItem(
        tween: Tween<Offset>(begin: const Offset(0.0, 0), end: const Offset(-1.0, 0)),
        weight: 1000.0,
      ),
    ]).animate(animationController);

    // 透明度动画:前两段保持不透明,最后一段渐变消失
    opacityAnimation = TweenSequence([
      TweenSequenceItem(
        tween: ConstantTween<double>(1.0),
        weight: widget.duration.inMilliseconds.toDouble() + 2000.0,
      ),
      TweenSequenceItem(
        tween: Tween<double>(begin: 1.0, end: 0.0),
        weight: 1000.0,
      ),
    ]).animate(animationController);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        // 点击播放按钮启动动画,from:0支持重复触发
        animationController.forward(from: 0);
      },
      child: FadeTransition(
        opacity: opacityAnimation,
        child: SlideTransition(
          position: slideAnimation,
          child: getBarrageWidget(),
        ),
      ),
    );
  }

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

  Widget getBarrageWidget() {
    // 自定义组件示例,可替换为你的实际组件
    return Container(
      width: 100,
      height: 50,
      color: Colors.blue,
      child: const Center(child: Text("弹幕")),
    );
  }
}

方案二:分阶段监听动画状态执行

这种方式更灵活,适合需要动态调整等待时长或动画参数的场景:

class YourWidget extends StatefulWidget {
  final Duration duration;
  const YourWidget({super.key, required this.duration});

  @override
  State<YourWidget> createState() => _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> with SingleTickerProviderStateMixin {
  late AnimationController animationController;
  late Animation<Offset> slideAnimation;
  late Animation<double> opacityAnimation;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(duration: widget.duration, vsync: this);
    // 初始化第一段动画:位置1→位置2
    slideAnimation = Tween<Offset>(begin: const Offset(1.0, 0), end: const Offset(0.0, 0)).animate(animationController);
    opacityAnimation = Tween<double>(begin: 1.0, end: 1.0).animate(animationController);

    // 监听第一段动画完成事件
    animationController.addStatusListener((status) async {
      if (status == AnimationStatus.completed) {
        // 等待指定时长
        await Future.delayed(const Duration(seconds: 2));
        // 重置控制器,配置第二段动画:位置2→位置3+消失
        setState(() {
          animationController.reset();
          animationController.duration = const Duration(seconds: 1);
          slideAnimation = Tween<Offset>(begin: const Offset(0.0, 0), end: const Offset(-1.0, 0)).animate(animationController);
          opacityAnimation = Tween<double>(begin: 1.0, end: 0.0).animate(animationController);
        });
        // 启动第二段动画
        animationController.forward();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        animationController.forward(from: 0);
      },
      child: FadeTransition(
        opacity: opacityAnimation,
        child: SlideTransition(
          position: slideAnimation,
          child: getBarrageWidget(),
        ),
      ),
    );
  }

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

  Widget getBarrageWidget() {
    return Container(
      width: 100,
      height: 50,
      color: Colors.blue,
      child: const Center(child: Text("弹幕")),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:53:22