Search code examples
flutterflutter-macos-2.0.0-stable

Dismissing dialog with Escape key with nested navigator


I'm writing a Flutter app targeted towards macOS and want to be able to show a modal dialog that allows navigation within that dialog (somewhat like a sequence of onboarding screens).

In order to facilitate the navigation within the dialog, I need to wrap my widgets in a navigator of some sort. See the following (simplified) code:

showDialog(
  context: context,
  builder: (context) => Dialog(
    child: SizedBox(
      width: 400,
      height: 400,
      child: Navigator(
        onGenerateRoute: (_) => MaterialPageRoute(
          builder: (_) => const Center(child: Text('hi there'))
        ),
      ),
    ),
  ),
);

Now this works perfectly - except for dismissal. I can dismiss the dialog by tapping in the barrier area (which is good), however, pressing ESC on the keyboard doesn't dismiss the dialog.

If I just embed the child directly (without the navigator), pressing ESC dismisses the dialog perfectly. But for some reason, it looks like Navigator is swallowing the ESC key. I've also tried using MaterialApp as the navigator and it also eats the ESC key.

Any theories on how I can get the navigator to let me dismiss the dialog using the ESC key? Thanks


Solution

  • You can use a RawKeyboardListener to listen to keypresses, and pop when an ESC event fired.

    Old response that didn't work: Try wrapping the widget inside the page route (in this case, the Center) with a WillPopScope. You should be able to receive the ESC event on the onWillPop callback before the inner Navigator receives it, then you can call pop on the outer Navigator to dismiss the dialog.