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

如何通过多个Tween为同一属性分阶段提供动画值?

解决Flutter同一属性多段Tween动画覆盖问题

方案一:使用TweenSequence(官方推荐)

TweenSequence专门用于组合多段连续动画,支持为每个片段设置时间权重,完美匹配你的分段动画需求。修改后的代码如下:

class TextAnimation extends StatelessWidget {
  const TextAnimation({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Animation<double> yOffset = TweenSequence<double>(
      [
        TweenSequenceItem(
          tween: Tween<double>(begin: 0.0, end: 180.0)
              .chain(CurveTween(curve: Curves.easeIn)),
          weight: 0.5, // 对应总动画时长的50%
        ),
        TweenSequenceItem(
          tween: Tween<double>(begin: 180.0, end: -100.0)
              .chain(CurveTween(curve: Curves.easeOut)),
          weight: 0.5, // 对应总动画时长的50%
        ),
      ],
    ).animate(animationController);

    return AnimatedBuilder(
      animation: animationController,
      builder: (context, child) {
        return Transform.translate(
          offset: Offset(0, yOffset.value),
          child: const Text("Hello"),
        );
      },
    );
  }
}

注意:第二段Tween的begin需与第一段的end保持一致,保证动画衔接流畅;weight比例对应你原本的Interval区间,比如0.5对应0.0-0.5的时间范围。

方案二:手动根据动画控制器值计算

若不想依赖Tween,可直接读取animationController.value(范围0.0-1.0),判断当前时间区间后手动计算属性值,灵活性更高:

class TextAnimation extends StatelessWidget {
  const TextAnimation({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animationController,
      builder: (context, child) {
        double y;
        final progress = animationController.value;
        if (progress <= 0.5) {
          // 0.0-0.5阶段:从0到180,应用easeIn曲线
          final segmentProgress = Curves.easeIn.transform(progress * 2);
          y = 0.0 + (180.0 - 0.0) * segmentProgress;
        } else {
          // 0.5-1.0阶段:从180到-100,应用easeOut曲线
          final segmentProgress = Curves.easeOut.transform((progress - 0.5) * 2);
          y = 180.0 + (-100.0 - 180.0) * segmentProgress;
        }
        return Transform.translate(
          offset: Offset(0, y),
          child: const Text("Hello"),
        );
      },
    );
  }
}

方案三:保留多个Animation变量,按需取值

不覆盖原有Animation对象,定义两个独立变量,在builder中根据控制器当前值判断使用哪段动画的结果:

class TextAnimation extends StatelessWidget {
  const TextAnimation({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Animation<double> yOffset1 = Tween<double>(
      begin: 0.0,
      end: 180.0,
    ).animate(
      CurvedAnimation(
        parent: animationController,
        curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
      ),
    );

    final Animation<double> yOffset2 = Tween<double>(
      begin: 180.0,
      end: -100.0,
    ).animate(
      CurvedAnimation(
        parent: animationController,
        curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
      ),
    );

    return AnimatedBuilder(
      animation: animationController,
      builder: (context, child) {
        final y = animationController.value <= 0.5 ? yOffset1.value : yOffset2.value;
        return Transform.translate(
          offset: Offset(0, y),
          child: const Text("Hello"),
        );
      },
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:55:27