【问题标题】:Flutter Navigation doesn't pop Navigator stack on back pressFlutter Navigation 不会在后按时弹出 Navigator 堆栈
【发布时间】:2021-10-11 01:08:17
【问题描述】:

我正在使用Navigator 命名路由,以使用BottomNavigationBar 在屏幕上切换页面。在第 3 页,我可以通过 NavigationKey.currentState.pushNamed(Page4Route) 导航到第 4 页。

在第 4 页上,我可以通过调用 NavigationKey.currentState.pop 导航回第 3 页,但按下设备的后退按钮会关闭应用程序。知道为什么后退按钮不会在导航堆栈上弹出当前屏幕吗?我怎样才能更好地处理这个问题?

Widget build(BuildContext context) {
  return Scaffold(
    body: Navigator(
      key: navigationKey,
      initialRoute: Pages.home,
      onGenerateRoute: (RouteSettings settings) {
        WidgetBuilder builder;
        // Manage your route names here
        switch (settings.name) {
          case Pages.home:
            builder = (BuildContext context) => _page1();
            break;
          case Pages.page1:
            builder = (BuildContext context) => _page1();
            break;
          case Pages.page2:
            builder = (BuildContext context) => _page2();
            break;
          case Pages.page3:
            builder = (BuildContext context) => _page3();
            break;
          case Pages.page4:
            builder = (BuildContext context) => Page4Screen(navigatorKey: navigationKey);
            break;
          default:
            throw Exception('Invalid route: ${settings.name}');
        }
        return MaterialPageRoute(
          builder: builder,
          settings: settings,
       );
      },
    ),
    bottomNavigationBar: BottomNavigationBar(),
    ...
  );
}

演示

最小复制

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nested Routing Demo',
      home: HomePage(),
    );
  }
}

class Pages{
  static const home = '/';
  static const page1 = '/page1';
  static const page2 = '/page2';
  static const page3 = '/page3';
  static const page4 = '/page4';
}

class HomePage extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<HomePage> {
  final GlobalKey<NavigatorState> navigationKey = GlobalKey<NavigatorState>();
  var _currentPage = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Navigator(
        key: navigationKey,
        initialRoute: '/',
        onGenerateRoute: (RouteSettings settings) {
          WidgetBuilder builder;
          // Manage your route names here
          switch (settings.name) {
            case Pages.home:
              builder = (BuildContext context) => _page1();
              break;
            case Pages.page1:
              builder = (BuildContext context) => _page1();
              break;
            case Pages.page2:
              builder = (BuildContext context) => _page2();
              break;
            case Pages.page3:
              builder = (BuildContext context) => _page3();
              break;
            case Pages.page4:
              builder = (BuildContext context) => Page4Screen(navigatorKey: navigationKey);
              break;
            default:
              throw Exception('Invalid route: ${settings.name}');
          }
          // You can also return a PageRouteBuilder and
          // define custom transitions between pages
          return MaterialPageRoute(
            builder: builder,
            settings: settings,
          );
        },
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.mood),
            label: 'Page 1',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.connect_without_contact),
            label: 'Page 2',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.message),
            label: 'Page 3',
          ),
        ],
        currentIndex: _currentPage,
        // selectedItemColor: Colors.amber[800],
        onTap: (value) {
          /// Update page if a different tab from the current was clicked
          if (value != _currentPage)
            setState(() {
              _currentPage = value;
              switch (value) {
                case 0:
                  navigationKey.currentState!
                      .pushReplacementNamed(Pages.page1);
                  break;
                case 1:
                  navigationKey.currentState!
                      .pushReplacementNamed(Pages.page2);
                  break;
                case 2:
                  navigationKey.currentState!
                      .pushReplacementNamed(Pages.page3);
                  break;
                default:

                /// TODO Error 404 page
                  throw Exception('Invalid route: $value');
              }
            });
        },
      ),
    );
  }

  Widget _page1() {
    return Scaffold(
      body: Container(
        color: Colors.lightBlueAccent,
        child: Center(
          child: Text('Page 1'),
        ),
      ),
    );
  }

  Widget _page2() {
    return Scaffold(
      body: Container(
        color: Colors.orangeAccent,
        child: Center(
          child: Text('Page2'),
        ),
      ),
    );
  }

  Widget _page3() {
    return Scaffold(
      body: Container(
        color: Colors.lightGreenAccent,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Page 3'),
              ElevatedButton(onPressed: (){
                navigationKey.currentState!.pushNamed(Pages.page4);
              }, child: Text('Page 4')),
            ],
          ),
        ),
      ),
    );
  }
}

class Page4Screen extends StatefulWidget {
  Page4Screen({Key? key, required GlobalKey<NavigatorState> navigatorKey}) : _navigatorKey = navigatorKey, super(key: key);
  final GlobalKey<NavigatorState> _navigatorKey;
  @override
  createState() => Page4State();
}

class Page4State extends State<Page4Screen>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // appBar: AppBar(
      //   title: Text(AppLocalizations.of(context)!.txtTitleMood),
      //   automaticallyImplyLeading: false,
      // ),
      body: Container(
        color: Colors.redAccent,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Page 4'),ElevatedButton(
                // Within the SecondScreen widget
                onPressed: () {
                  // Navigate back to the first screen by popping the current route
                  // off the stack.
                  widget._navigatorKey.currentState!.pop();
                },
                child: Text('Go Back!'),
              ),
            ],
          ),

        ),
      ),
    );
  }
}

【问题讨论】:

  • 你正在使用pushReplacementNamed,它将覆盖路由。
  • 改用pushNamed
  • @OMiShah 我使用 pushNamed 导航到第 4 页。您可以在 Widget _page3() 上看到这个

标签: flutter flutter-navigation


【解决方案1】:

Navigator 小部件默认不处理后退按钮,如果您定义了 Navigator 小部件,这就是您的工作。您可以通过WillPopScope 小部件赶上回击。它需要一个Future&lt;bool&gt; Function(),每当用户想要返回时都会调用它。如果它返回 false,那么位于 MaterialApp 中的默认 Navigator 将不会弹出当前路由,在这种情况下仅显示您的 HomePage。因此,如果您的嵌套导航器有要弹出的内容(例如 Page4),那么它将弹出该内容并阻止您的主要 Navigator 弹出您的 HomePage

class _HomeState extends State<HomePage> {
  ...

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => !(await navigationKey.currentState!.maybePop()),
      child: Scaffold(
        ...
      ),
    );
  }
}

【讨论】:

  • navigationKey.currentState!.maybePop() 在初始应用启动时返回 true。这是为什么?这会导致这种行为:!Demo willPop!Demo willPop navigation
  • 你确定你使用的是我写的代码吗?因为我正在测试它并且它工作正常。不要忘记非运算符 (!)。 @Omatt
  • 我发现了问题。看起来initialRoute 应该设置为'/'。如果 initialRoute 设置了名称,即 '/route',则导航器将 currentState.maybePop() 返回为 true。我再次对其进行了测试,代码现在按预期工作。非常感谢!
  • 不客气。顺便说一句,我从来没有这样测试过。很高兴知道。 @Omatt
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2020-04-02
  • 2018-10-21
  • 2021-02-12
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
相关资源
最近更新 更多