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

如何移除Flutter Navigator 2.0嵌套导航器的Elevation效果

解决嵌套Navigator的Elevation问题

你遇到的这个问题是因为Flutter的MaterialPage默认会给页面包裹一个带有elevation的Material组件,当嵌套导航器切换页面时,这个elevation就会显示为突兀的阴影效果。下面给你几种简单的解决方法:

方法1:使用NoTransitionPage替代MaterialPage

这是最直接的方案,NoTransitionPage不会添加默认的Material外壳和过渡效果,自然也就没有elevation。修改你的NestedRouterDelegate中的pages部分:

@override
Widget build(BuildContext context) {
  return Navigator(
    key: _nestedNavigatorKey,
    observers: [HeroController()],
    pages: [
      if (selectedIndex == 0) NoTransitionPage(
        key: ValueKey('ProfilePage'),
        child: ProfileWidget(
          onPressed: () {},
        ),
      ),
      if (selectedIndex == 1) NoTransitionPage(
        key: ValueKey('SettingWidget'),
        child: SettingWidget(),
      ),
    ],
    onPopPage: (route, result) {
      print('onPopPage NestedRouterDelegate');
      return false;
    },
  );
}

方法2:自定义页面路由去掉elevation

如果你还需要保留页面过渡效果,只是想去掉elevation,可以用PageRouteBuilder自定义路由,同时覆盖默认的Material外壳:

@override
Widget build(BuildContext context) {
  return Navigator(
    key: _nestedNavigatorKey,
    observers: [HeroController()],
    pages: [
      if (selectedIndex == 0) PageRouteBuilder(
        key: ValueKey('ProfilePage'),
        pageBuilder: (context, animation, secondaryAnimation) => Material(
          elevation: 0,
          child: ProfileWidget(onPressed: (){}),
        ),
        // 如果你需要过渡效果,可以自定义transitionsBuilder,这里直接返回child去掉过渡
        transitionsBuilder: (context, animation, secondaryAnimation, child) => child,
      ),
      if (selectedIndex == 1) PageRouteBuilder(
        key: ValueKey('SettingWidget'),
        pageBuilder: (context, animation, secondaryAnimation) => Material(
          elevation: 0,
          child: SettingWidget(),
        ),
        transitionsBuilder: (context, animation, secondaryAnimation, child) => child,
      ),
    ],
    onPopPage: (route, result) {
      print('onPopPage NestedRouterDelegate');
      return false;
    },
  );
}

方法3:在页面组件中手动覆盖elevation

如果你不想修改路由类型,可以在每个页面的Scaffold外层包裹一个elevation为0的Material组件,覆盖默认的elevation:

比如修改ProfileWidget:

class ProfileWidget extends StatelessWidget {
  final VoidCallback onPressed;
  ProfileWidget({required this.onPressed}) : super();

  @override
  Widget build(BuildContext context) {
    return Material(
      elevation: 0,
      child: Scaffold(
        // 你的页面原有内容
      ),
    );
  }
}

同样的方法应用到SettingWidget即可。

推荐使用第一种方法,它最简洁且从根源上避免了默认的elevation问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:07:37