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

如何使用Navigator 2.0实现页面替换时的过渡动画效果

问题根因

Flutter Navigator 2.0 的内置过渡动画默认仅在 pages 数组长度发生变化(新增/删除页面元素)时触发。你每次替换 pages 数组的唯一元素时,数组长度没有变化,因此不会触发动画逻辑。

可行解决方案

方案1:自定义带过渡的Page,无需维护多页面元素

继承 Page 类实现强制过渡动画的自定义页面,直接替换原有 MaterialPage 即可,不需要修改 pages 数组长度,也不需要维护额外的页面栈。

import 'package:flutter/material.dart';

class AnimatedReplacePage extends Page {
  final Widget child;

  const AnimatedReplacePage({
    required this.child,
    LocalKey? key,
  }) : super(key: key);

  @override
  Route createRoute(BuildContext context) {
    return PageRouteBuilder(
      settings: this,
      transitionDuration: const Duration(milliseconds: 400),
      reverseTransitionDuration: const Duration(milliseconds: 400),
      pageBuilder: (context, animation, secondaryAnimation) => child,
      // 可自行替换为你需要的过渡效果,以下是iOS风格右滑进入效果
      transitionsBuilder: (context, animation, secondaryAnimation, child) {
        final tween = Tween(begin: const Offset(1.0, 0.0), end: Offset.zero)
            .chain(CurveTween(curve: Curves.easeOut));
        return SlideTransition(
          position: animation.drive(tween),
          child: child,
        );
      },
    );
  }
}

替换后的Navigator配置:

final page = ...
return Scaffold(
  body: Navigator(
    onPopPage: (Route<dynamic> route, dynamic result) {
      return route.didPop(result);
    },
    pages: [
      // 每次页面更新时传入唯一key,用于识别页面变化
      AnimatedReplacePage(
        key: ValueKey(page.runtimeType),
        child: page,
      ),
    ],
  ),
  ...
);

方案2:极简适配,临时触发长度变化

如果不想自定义Page,只需要在页面切换时临时保留旧页面元素,等动画播放完成后自动移除即可,仅需要维护一个当前页面变量,不需要手动管理完整页面栈。

// 状态变量定义
Widget currentPage = const HomePage();
Widget? _tempPreviousPage;

// 页面切换方法
void updatePage(Widget newPage) {
  _tempPreviousPage = currentPage;
  currentPage = newPage;
  setState(() {});
  // 动画结束后清空临时旧页面
  Future.delayed(const Duration(milliseconds: 400), () {
    _tempPreviousPage = null;
    setState(() {});
  });
}

// Navigator配置
body: Navigator(
  onPopPage: (route, result) => route.didPop(result),
  pages: [
    if (_tempPreviousPage != null) MaterialPage(child: _tempPreviousPage!),
    MaterialPage(child: currentPage),
  ],
)

该方案利用pages数组长度从1变为2触发系统自带的页面过渡动画,动画结束后自动恢复为1个页面元素,无需额外维护栈逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:27:02