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

请求指导:在Flutter Navigation 2.0中使用TransitionDelegate自定义页面转场动画(如bounceOut)

Hey there! 作为刚上手Flutter Navigation 2.0的新手,确实会被它的声明式逻辑绕晕,尤其是转场动画这块——毕竟和1.0的命令式路由玩法差异挺大的。你遇到的问题其实非常典型:Navigation 2.0是基于Page对象而非Route对象来管理页面栈的,所以直接用MaterialPageRoute替换MaterialPage肯定行不通,因为Navigator.pages只接受Page类型。下面我给你两种可行的实现方案,帮你搞定bounceOut这类自定义转场动画:

方案一:自定义带转场的Page类(快速实现单个页面的自定义转场)

这个方案最直观,核心是让自定义Page自己生成带转场效果的Route,Navigation 2.0的Navigator会自动复用这个Route的转场逻辑。

1. 定义自定义Page类

class CustomTransitionPage<T> extends Page<T> {
  final Widget child;
  final Curve exitCurve; // 退出动画曲线,这里我们用bounceOut
  final Curve enterCurve;

  const CustomTransitionPage({
    required this.child,
    this.exitCurve = Curves.bounceOut,
    this.enterCurve = Curves.linear,
    super.key,
    super.name,
    super.arguments,
    super.restorationId,
  });

  @override
  Route<T> createRoute(BuildContext context) {
    return PageRouteBuilder<T>(
      settings: this, // 必须传递当前Page的settings,保证Navigation 2.0栈状态正确
      transitionDuration: const Duration(milliseconds: 800),
      reverseTransitionDuration: const Duration(milliseconds: 800),
      // 页面内容构建
      pageBuilder: (context, animation, secondaryAnimation) => child,
      // 转场动画构建
      transitionsBuilder: (context, animation, secondaryAnimation, child) {
        // secondaryAnimation对应栈顶页面的退出动画
        final exitAnimation = ReverseAnimation(secondaryAnimation).drive(
          CurveTween(curve: exitCurve),
        );
        // animation对应新页面的进入动画
        final enterAnimation = animation.drive(
          CurveTween(curve: enterCurve),
        );

        // 这里用缩放动画示例,你可以替换成滑动、渐变等任意动画
        return ScaleTransition(
          scale: exitAnimation, // 旧页面退出时用bounceOut缩放
          child: ScaleTransition(
            scale: enterAnimation, // 新页面进入时线性缩放
            child: child,
          ),
        );
      },
    );
  }
}

2. 在Navigation 2.0中使用

把原来的MaterialPage替换成这个自定义Page即可:

Navigator(
  pages: [
    CustomTransitionPage(child: HomeScreen()),
    // 当需要跳转到详情页时,添加这个页面
    if (isShowingDetails) CustomTransitionPage(child: DetailsScreen()),
  ],
  onPopPage: (route, result) {
    if (!route.didPop(result)) return false;
    // 这里处理你的栈状态更新逻辑,比如将isShowingDetails设为false
    return true;
  },
)

方案二:自定义TransitionDelegate(全局统一控制转场)

如果想让整个应用的页面退出都使用bounceOut动画,或者根据不同Page类型设置差异化转场,自定义TransitionDelegate会更灵活。

1. 定义自定义TransitionDelegate

class BounceOutTransitionDelegate extends TransitionDelegate<void> {
  @override
  Iterable<RouteTransitionRecord> resolve({
    required List<RouteTransitionRecord> newPageRouteHistory,
    required Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
    required Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
  }) {
    final List<RouteTransitionRecord> results = [];

    // 处理所有退出的页面,给它们添加bounceOut动画
    for (final exitingRecord in locationToExitingPageRoute.values) {
      if (exitingRecord.isWaitingForEnteringDecision) {
        exitingRecord.markForPop(exitingRecord.route.currentResult);
        // 设置退出动画曲线为bounceOut
        exitingRecord.pushReplacementTransition =
          CurvedAnimation(parent: exitingRecord.animation!, curve: Curves.bounceOut);
      }
      results.add(exitingRecord);
    }

    // 处理所有进入的页面,使用默认进入动画
    for (final pageRoute in newPageRouteHistory) {
      if (pageRoute.isWaitingForExitingDecision) {
        pageRoute.markForAdd();
      }
      results.add(pageRoute);
    }

    return results;
  }
}

2. 在Navigator中启用这个Delegate

Navigator(
  transitionDelegate: BounceOutTransitionDelegate(),
  pages: [
    MaterialPage(child: HomeScreen()),
    if (isShowingDetails) MaterialPage(child: DetailsScreen()),
  ],
  onPopPage: (route, result) {
    if (!route.didPop(result)) return false;
    // 更新栈状态逻辑
    return true;
  },
)

几个关键注意点

  • 不管用哪种方案,onPopPage方法必须正确处理栈状态更新,否则Navigation 2.0的页面栈会出现异常。
  • 如果需要更复杂的动画组合(比如缩放+渐变),可以在transitionsBuilder里嵌套多个动画组件,或者使用flutter_animate这类库简化代码。
  • 测试时要确保页面栈的触发逻辑正确(比如isShowingDetails的状态变化),否则可能看不到预期的转场效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:14:05