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

Flutter中能否用NavigatorObserver动态修改GoRouter页面过渡类型?

用NavigatorObserver实现动态导航过渡动画

完全可行,但NavigatorObserver本身只负责监听导航事件(如路由入栈/出栈),不直接控制路由的过渡动画。要实现动态修改过渡效果,需要让Observer存储当前过渡类型状态,再配合自定义路由或路由生成器,在创建路由时读取Observer的状态来应用对应动画。

实现步骤

1. 定义过渡类型枚举

enum TransitionType { fade, slide }

2. 创建自定义NavigatorObserver

这个Observer负责存储当前过渡类型,并提供修改方法:

class TransitionObserver extends NavigatorObserver {
  TransitionType _currentType = TransitionType.fade;

  TransitionType get currentType => _currentType;

  void setTransitionType(TransitionType type) {
    _currentType = type;
    // 路由生成时会直接读取最新值,无需额外通知状态变化
  }
}

3. 实现自定义过渡路由

根据Observer的状态,生成对应过渡效果的路由:

class CustomTransitionRoute<T> extends MaterialPageRoute<T> {
  final TransitionType transitionType;

  CustomTransitionRoute({
    required WidgetBuilder builder,
    required this.transitionType,
    RouteSettings? settings,
  }) : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    switch (transitionType) {
      case TransitionType.fade:
        return FadeTransition(opacity: animation, child: child);
      case TransitionType.slide:
        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(1.0, 0.0),
            end: Offset.zero,
          ).animate(animation),
          child: child,
        );
    }
  }
}

4. 配置MaterialApp并关联Observer

把Observer实例传入navigatorObservers,同时在onGenerateRoute中读取Observer的状态生成路由:

void main() {
  final transitionObserver = TransitionObserver();
  runApp(MyApp(observer: transitionObserver));
}

class MyApp extends StatelessWidget {
  final TransitionObserver observer;

  const MyApp({super.key, required this.observer});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [observer],
      onGenerateRoute: (settings) {
        Widget page;
        switch (settings.name) {
          case '/second':
            page = const SecondPage();
            break;
          default:
            page = const HomePage();
        }
        return CustomTransitionRoute(
          builder: (context) => page,
          transitionType: observer.currentType,
          settings: settings,
        );
      },
      home: const HomePage(),
    );
  }
}

5. 动态修改过渡类型

在任意页面中,通过获取Observer实例调用setTransitionType即可:

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

  @override
  Widget build(BuildContext context) {
    final observer = Navigator.of(context).observers.firstWhere(
      (o) => o is TransitionObserver,
    ) as TransitionObserver;

    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () {
              observer.setTransitionType(TransitionType.fade);
              Navigator.pushNamed(context, '/second');
            },
            child: const Text('跳转到第二页(淡入)'),
          ),
          ElevatedButton(
            onPressed: () {
              observer.setTransitionType(TransitionType.slide);
              Navigator.pushNamed(context, '/second');
            },
            child: const Text('跳转到第二页(滑入)'),
          ),
        ],
      ),
    );
  }
}

关键说明

  • NavigatorObserver的核心作用是监听导航生命周期,我们只是借它存储全局过渡状态,真正的过渡逻辑在自定义路由中实现。
  • 相比用StatefulWidget包裹Navigator的方式,这种方案更贴合Flutter导航系统设计,无需额外嵌套层级,状态管理更集中。
  • 如果使用Provider、GetX等状态管理工具,也可以把过渡类型放到全局状态中,Observer仅负责监听,但直接用Observer存储状态已经足够轻量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:03:17