Skip to content

onPopInvoked not called when using Navigator.pages #141189

@justinmc

Description

@justinmc

Steps to reproduce

  1. Run the app below, which uses Navigator.pages for routing and has a page with a PopScope widget.
  2. Navigate to the PopScope page and press the back button or perform a back gesture.

Expected results

onPopInvoked should have been called.

Actual results

onPopInvoked is not called. The back navigation does correctly happen, but the callback isn't called.

It does get called if popping is blocked, but not when it's successful.

In comparison try the other page, which uses WillPopScope. onWillPop is called in both situations.

Code sample

Code sample
import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

enum _Page {
  home,
  two,
  three,
}

void main() {
  runApp(const _MyApp());
}

class _MyApp extends StatefulWidget {
  const _MyApp();
  
  @override
  State<_MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<_MyApp> {
  final List<_Page> _pages = <_Page>[_Page.home];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Navigator(
        onPopPage: (Route<void> route, void result) {
          if (!route.didPop(null)) {
            return false;
          }
          setState(() {
            _pages.removeLast();
          });
          return true;
        },
        pages: _pages.map((_Page page) {
          switch (page) {
            case _Page.home:
              return MaterialPage(
                child: Scaffold(
                  backgroundColor: darkBlue,
                  body: Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        const Text('Home'),
                        TextButton(
                          onPressed: () {
                            setState(() {
                              _pages.add(_Page.two);
                            });
                          },
                          child: const Text('Go to PopScope page'),
                        ),
                        TextButton(
                          onPressed: () {
                            setState(() {
                              _pages.add(_Page.three);
                            });
                          },
                          child: const Text('Go to WillPopScope page'),
                        ),
                      ],
                    ),
                  ),
                ),
              );
            case _Page.two:
              return MaterialPage(
                child: _MyPopScopePage(),
              );
            case _Page.three:
              return MaterialPage(
                child: _MyWillPopScopePage(),
              );
          }
        }).toList(),
      ),
    );
  }
}

class _MyPopScopePage extends StatefulWidget {
  @override
  State<_MyPopScopePage> createState() => _MyPopScopePageState();
}

class _MyPopScopePageState extends State<_MyPopScopePage> {
  var canPop = true;

  @override
  Widget build(BuildContext context) => PopScope(
    canPop: canPop,
    onPopInvoked: (didPop) {
      print('PopScope onPopInvoked called. didPop=$didPop');
    },
    child: Scaffold(
      body: Column(
        children: [
          const ListTile(title: Text('You Are Next')),
          ListTile(
            onTap: () => Navigator.maybePop(context),
            title: const Text('Go Back'),
          ),
          CheckboxListTile(
            value: canPop,
            onChanged: (value) => setState(() {
              canPop = value!;
            }),
            title: const Text('Toggle canPop'),
          ),
        ],
      ),
    ),
  );
}


class _MyWillPopScopePage extends StatefulWidget {
  @override
  State<_MyWillPopScopePage> createState() => _MyWillPopScopePageState();
}

class _MyWillPopScopePageState extends State<_MyWillPopScopePage> {
  var canPop = true;

  @override
  Widget build(BuildContext context) => WillPopScope(
    onWillPop: () async {
      print('WillPopScope onWillPop called.');
      return canPop;
    },
    child: Scaffold(
      body: Column(
        children: [
          const ListTile(title: Text('You Are Next - WillPopScope page')),
          ListTile(
            onTap: () => Navigator.maybePop(context),
            title: const Text('Go Back'),
          ),
          CheckboxListTile(
            value: canPop,
            onChanged: (value) => setState(() {
              canPop = value!;
            }),
            title: const Text('Toggle canPop'),
          ),
        ],
      ),
    ),
  );
}

References

Google: b/309771402

Metadata

Metadata

Assignees

Labels

f: routesNavigator, Router, and related APIs.found in release: 3.16Found to occur in 3.16found in release: 3.18Found to occur in 3.18frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions