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

Android端实现类iOS风格Flutter页面转场动画方案咨询

在Android端实现类Cupertino页面转场动画的可行方案

问题分析

直接配置PageTransitionsTheme使用CupertinoPageTransitionsBuilder作为Android平台的转场构建器,效果不符合预期;自行通过Stack堆叠前后页面实现动画时,前进转场正常,但返回时会短暂显示堆叠的旧页面后消失。

解决方案一:自定义适配Android的Cupertino风格转场构建器

可以自定义一个PageTransitionsBuilder,完全复刻Cupertino的转场逻辑,同时适配Android平台的路由行为:

class AndroidCupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
  const AndroidCupertinoPageTransitionsBuilder();

  @override
  Widget buildTransitions<T>(
    PageRoute<T> route,
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    return CupertinoPageTransition(
      primaryRouteAnimation: animation,
      secondaryRouteAnimation: secondaryAnimation,
      linearTransition: false,
      child: child,
    );
  }
}

然后在主题中配置:

pageTransitionsTheme: const PageTransitionsTheme(
  builders: {
    TargetPlatform.android: AndroidCupertinoPageTransitionsBuilder(),
  },
),

这个方法直接复用Flutter内置的CupertinoPageTransition组件,保证动画逻辑和iOS端一致,同时解决直接使用CupertinoPageTransitionsBuilder在Android上的适配问题。

解决方案二:修复自定义Stack堆叠的转场问题

如果坚持自己实现堆叠页面的动画,需要处理返回时的反向动画逻辑,核心是利用secondaryAnimation处理前页面的退场动画,同时区分路由的push和pop状态:

class CustomCupertinoRoute extends PageRouteBuilder {
  final Widget page;

  CustomCupertinoRoute({required this.page})
      : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            // 前进动画(push)的页面入场逻辑
            final pushEnter = Tween<Offset>(
              begin: const Offset(1.0, 0.0),
              end: Offset.zero,
            ).animate(animation);

            // 返回动画(pop)的前页面入场逻辑
            final popExit = Tween<Offset>(
              begin: Offset.zero,
              end: const Offset(-0.3, 0.0),
            ).animate(secondaryAnimation);

            return Stack(
              children: [
                // 仅在push阶段显示前页面的退场动画,避免返回时异常显示
                if (animation.status != AnimationStatus.reverse)
                  SlideTransition(
                    position: popExit,
                    child: Navigator.of(context).previousRoute?.child ?? const SizedBox(),
                  ),
                // 当前页面的入场/退场动画
                SlideTransition(
                  position: pushEnter,
                  child: Material(
                    elevation: 10.0 * animation.value,
                    child: child,
                  ),
                ),
              ],
            );
          },
        );
}

使用时直接用这个自定义路由跳转:

Navigator.push(context, CustomCupertinoRoute(page: NextPage()));

这里的关键是通过animation.status判断当前是push还是pop状态,避免返回时旧页面的异常显示,同时用secondaryAnimation处理反向动画的时序。

额外注意事项

  • 如果需要支持侧滑返回手势,自定义路由时需要重写buildPage和canPop方法,结合CupertinoGestureDetector实现手势逻辑。
  • 测试时要覆盖push、pop、replace等多种路由操作场景,确保动画在所有情况下都正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:37:49