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

如何实现融合Flutter OpenContainer与Hero动画的自定义过渡效果?

自定义实现OpenContainer + Hero动画融合效果

核心思路

因为官方OpenContainer组件本身不支持Hero动画,我们可以拆分两个核心效果分别实现再整合:

  • 用Hero组件负责共享元素的无缝过渡
  • 自定义路由过渡动画,模拟OpenContainer的"从按钮展开至全屏"的缩放+位置偏移效果
  • 将Hero的共享元素作为过渡动画的载体,让两个效果同步执行

代码实现步骤

1. 定义共享Hero标签

const _expandHeroTag = 'expand_button_tag';

2. 首页按钮(带Hero+触发跳转)

// 用GlobalKey获取按钮实际位置(可选,用于更精准的位置过渡)
final buttonGlobalKey = GlobalKey();

Hero(
  tag: _expandHeroTag,
  child: ElevatedButton(
    key: buttonGlobalKey,
    style: ElevatedButton.styleFrom(
      fixedSize: const Size(200, 60),
      backgroundColor: Colors.blue,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
    ),
    onPressed: () {
      Navigator.push(
        context,
        PageRouteBuilder(
          transitionDuration: const Duration(milliseconds: 500),
          reverseTransitionDuration: const Duration(milliseconds: 500),
          pageBuilder: (_, __, ___) => const FullScreenPage(),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            // 缩放动画:从按钮大小比例放大到全屏
            final scaleTween = Tween<double>(begin: 0.3, end: 1.0).animate(
              CurvedAnimation(parent: animation, curve: Curves.easeInOut),
            );
            
            // 位置偏移动画:让页面从按钮位置滑到全屏(可根据实际坐标动态计算)
            final offsetTween = Tween<Offset>(
              begin: const Offset(0, 0.5),
              end: Offset.zero,
            ).animate(
              CurvedAnimation(parent: animation, curve: Curves.easeInOut),
            );

            // 圆角过渡:模拟OpenContainer的圆角消失效果
            final borderRadiusTween = BorderRadiusTween(
              begin: BorderRadius.circular(8),
              end: BorderRadius.zero,
            ).animate(
              CurvedAnimation(parent: animation, curve: Curves.easeInOut),
            );

            return AnimatedBuilder(
              animation: borderRadiusTween,
              builder: (_, child) {
                return ClipRRect(
                  borderRadius: borderRadiusTween.value,
                  child: SlideTransition(
                    position: offsetTween,
                    child: ScaleTransition(
                      scale: scaleTween,
                      child: child,
                    ),
                  ),
                );
              },
              child: child,
            );
          },
        ),
      );
    },
    child: const Text('展开至全屏', style: TextStyle(color: Colors.white)),
  ),
)

3. 全屏目标页面

class FullScreenPage extends StatelessWidget {
  const FullScreenPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Hero(
        tag: _expandHeroTag,
        child: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.blue,
          child: Center(
            child: ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('返回', style: TextStyle(color: Colors.white)),
            ),
          ),
        ),
      ),
    );
  }
}

进阶优化

  • 精准位置计算:用buttonGlobalKey获取按钮的全局坐标,动态计算offsetTween的起始偏移量,让动画完全从按钮位置展开
  • 动画曲线调整:根据需求替换Curves参数,比如用Curves.elasticOut实现弹性展开效果
  • 状态同步:如果需要在过渡中同步更新内容,可以用AnimatedBuilder监听动画进度,实时修改组件状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:33:11