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

如何修复Flutter中Widget切换时的动画过渡不流畅问题?

修复AnimatedSwitcher切换时的组件错位问题

你的问题出在AnimatedSwitcher默认会让新旧组件在容器内居中对齐,当从小悬浮按钮切换到大型蓝色方块时,旧的悬浮按钮会被放置到新方块的中心位置,导致动画过程中出现错位。要实现平滑过渡,需要让两个组件始终锚定在同一个位置(右下角),同时调整动画的原点匹配这个锚点。

修复方案

  1. 用Align包裹两个子组件,强制它们都对齐到右下角,确保布局位置一致;
  2. 修改ScaleTransition的缩放原点,让动画从右下角开始,避免缩放过程中的位置偏移。

修改后的完整代码

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) {
        return Scaffold(body: Stack(children: [const AnimatedWidget()]));
      },
    );
  }
}

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

  @override
  AnimatedWidgetState createState() => AnimatedWidgetState();
}

class AnimatedWidgetState extends State<AnimatedWidget> {
  bool _isOpen = false;

  void toggleButton() {
    setState(() {
      _isOpen = !_isOpen;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      bottom: 20,
      right: 20,
      child: AnimatedSwitcher(
        duration: const Duration(milliseconds: 300),
        transitionBuilder: (child, animation) {
          return FadeTransition(
            opacity: animation.drive(const Tween(begin: 0.0, end: 1.0)),
            child: ScaleTransition(
              scale: animation,
              alignment: Alignment.bottomRight, // 缩放原点设为右下角
              child: child,
            ),
          );
        },
        child: _isOpen
            ? Align(
                alignment: Alignment.bottomRight,
                key: const ValueKey('square'),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    GestureDetector(
                      onTap: toggleButton,
                      child: const Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [Text('Close'), Icon(Icons.close)],
                      ),
                    ),
                    Container(
                      width: 300,
                      height: 300,
                      decoration: const BoxDecoration(
                          color: Colors.blue, shape: BoxShape.rectangle),
                      child: const Center(child: Text('This is square')),
                    ),
                  ],
                ),
              )
            : Align(
                alignment: Alignment.bottomRight,
                key: const ValueKey('add'),
                child: FloatingActionButton(
                  onPressed: toggleButton,
                  child: const Icon(Icons.add),
                ),
              ),
      ),
    );
  }
}

关键修改点

  • 给悬浮按钮和蓝色方块都添加Align组件,设置alignment: Alignment.bottomRight,确保两者始终锚定在右下角;
  • 在ScaleTransition中设置alignment: Alignment.bottomRight,让缩放动画从右下角开始,和组件的锚点一致,过渡更自然;
  • 给关闭按钮的Row添加mainAxisSize: MainAxisSize.min,避免Row占满宽度影响布局。

这样修改后,切换动画会从右下角平滑缩放过渡,不会出现组件错位的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:13:18