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

如何在Flutter中实现iOS Cupertino堆叠式全屏弹窗过渡效果?

实现iOS时钟应用的导航堆叠效果

现成组件方案

目前Flutter官方没有直接匹配该效果的组件,但可以使用第三方包flutter_cupertino_navigation_stack,它专门模拟iOS原生的导航堆叠过渡,包括时钟应用里新页面从底部滑入、旧页面保持堆叠的视觉效果。

自定义实现方案

如果不想依赖第三方包,可以基于PageRouteBuilder和动画自行实现:

1. 自定义路由类

创建继承自PageRoute的自定义路由,在buildTransitions方法中实现堆叠动画逻辑:

class IOSStackedRoute<T> extends PageRoute<T> {
  final WidgetBuilder builder;

  IOSStackedRoute({required this.builder})
      : super(settings: RouteSettings());

  @override
  Color? get barrierColor => null;

  @override
  String? get barrierLabel => null;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    return builder(context);
  }

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    // 新页面从底部滑入的动画
    final slideAnimation = Tween<Offset>(
      begin: const Offset(0, 1),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: animation,
      curve: Curves.easeInOut,
    ));

    // 旧页面的缩放+透明度变化,模拟堆叠效果
    final oldPageAnimation = Tween<double>(
      begin: 1.0,
      end: 0.9,
    ).animate(CurvedAnimation(
      parent: animation,
      curve: Curves.easeInOut,
    ));

    return Stack(
      children: [
        if (secondaryAnimation.status != AnimationStatus.completed)
          SlideTransition(
            position: Tween<Offset>(
              begin: Offset.zero,
              end: const Offset(0, -0.05),
            ).animate(secondaryAnimation),
            child: ScaleTransition(
              scale: oldPageAnimation,
              child: FadeTransition(
                opacity: oldPageAnimation,
                child: ModalRoute.of(context)?.previousContentWidget,
              ),
            ),
          ),
        SlideTransition(
          position: slideAnimation,
          child: child,
        ),
      ],
    );
  }

  @override
  bool get maintainState => true;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 300);
}

2. 使用自定义路由

在导航跳转时调用这个自定义路由:

Navigator.push(
  context,
  IOSStackedRoute(
    builder: (context) => YourTargetPage(),
  ),
);

3. 细节优化

  • 可根据需求调整动画曲线、时长、缩放比例和偏移量,让效果更贴近iOS原生表现
  • 上述代码已通过secondaryAnimation实现了页面关闭时的反向恢复动画

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:37:11