Flutter Navigation 不会在后按时弹出 Navigator 堆栈

Flutter Navigation doesn't pop Navigator stack on back press

我将 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!'),
              ),
            ],
          ),

        ),
      ),
    );
  }
}

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

class _HomeState extends State<HomePage> {
  ...

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