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

Flutter中实现起止值相同的动画方案咨询

解决Flutter中“先收缩再恢复”的起止值相同动画问题

你的问题核心出在动画执行顺序的控制逻辑上——你当前的代码里,_controller.forward()和_controller.reverse()几乎是同时触发的,因为Future.delayed并没有阻塞后续代码执行,导致动画刚要启动就被反向操作打断,自然看不到预期效果。下面给你几种靠谱的实现方式:

方案一:利用forward()的Future回调

AnimationController.forward()会返回一个Future,当动画执行完成时这个Future会完成,我们可以用then()链式调用reverse(),确保两个动画步骤顺序执行:

FlatButton(
  onPressed: () {
    setState(() {
      isSignUp = !isSignUp;
    });
    // 先执行forward动画,完成后自动触发reverse
    _controller.forward().then((_) => _controller.reverse());
  },
)

方案二:监听动画状态

通过给控制器添加状态监听器,当动画进入completed状态(即forward执行完毕)时,自动触发反向动画:

void initState() { 
  super.initState(); 
  _controller = AnimationController( 
    vsync: this, 
    duration: Duration(milliseconds: 1000), 
  ); 
  _insetAnimation = Tween<EdgeInsetsGeometry>( 
    begin: EdgeInsets.symmetric(horizontal: 0), 
    end: EdgeInsets.symmetric(horizontal: 500), 
  ).animate( 
    CurvedAnimation( 
      parent: _controller, 
      curve: Curves.bounceIn,
      // 可以给反向动画单独设置曲线,比如回弹效果
      reverseCurve: Curves.bounceOut,
    ), 
  ); 
  _insetAnimation.addListener(() => setState(() {}));
  
  // 添加状态监听器,控制动画流程
  _controller.addStatusListener((status) {
    if (status == AnimationStatus.completed) {
      _controller.reverse();
    }
  });
}

// 按钮点击只需触发forward即可
FlatButton(
  onPressed: () {
    setState(() {
      isSignUp = !isSignUp;
    });
    _controller.forward();
  },
)

方案三:用TweenSequence实现单次完整循环动画

如果不想手动控制forward和reverse,可以直接用TweenSequence定义一个“初始值→目标值→初始值”的完整动画序列,只需一次forward()就能完成整个收缩再恢复的过程:

void initState() { 
  super.initState(); 
  _controller = AnimationController( 
    vsync: this, 
    // 总时长为两段动画的时间之和,这里各1秒,总2秒
    duration: Duration(milliseconds: 2000), 
  ); 
  // 定义序列动画:先从0到500(占总时长50%),再从500回到0(占总时长50%)
  _insetAnimation = TweenSequence<EdgeInsetsGeometry>([
    TweenSequenceItem(
      tween: Tween<EdgeInsetsGeometry>(
        begin: EdgeInsets.symmetric(horizontal: 0),
        end: EdgeInsets.symmetric(horizontal: 500),
      ),
      weight: 1.0,
    ),
    TweenSequenceItem(
      tween: Tween<EdgeInsetsGeometry>(
        begin: EdgeInsets.symmetric(horizontal: 500),
        end: EdgeInsets.symmetric(horizontal: 0),
      ),
      weight: 1.0,
    ),
  ]).animate(
    CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    ),
  ); 
  _insetAnimation.addListener(() => setState(() {}));
}

// 按钮点击触发完整动画
FlatButton(
  onPressed: () {
    setState(() {
      isSignUp = !isSignUp;
    });
    // 先重置控制器,避免重复点击导致动画状态混乱
    _controller.reset();
    _controller.forward();
  },
)

额外提醒:如果用户可能多次点击按钮,建议在触发动画前调用_controller.reset(),避免动画状态叠加导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 14:52:46