skip to Main Content

Scenario

I would need to conditionally navigate to a screen and hence was using WillPopScope widget wrapped around the Scaffold widget in my app.

Code:

WillPopScope(
      onWillPop: () async {
        if (hasProfilePicUpdated) {
          Navigator.pushNamedAndRemoveUntil(
            context,
            Routes.dashboard,
            (route) => false,
            arguments: DashboardArgumentModel(
              onboardingState: dashboardArgumentModel.onboardingState,
            ).toMap(),
          );
        } else {
          Navigator.pop(context);
        }
        return false;
      },
      child: Scaffold(

With the code above, I was able to navigate to my desired screen. Now after I upgraded Flutter to 3.16.1, I got a warning that WillPopScope is deprecated and that I should use PopScope. Hence, I updated my code to as below:

Code:

PopScope(
      // canPop: true, - this makes no difference
      onPopInvoked: (val) async {
        if (hasProfilePicUpdated) {
          Navigator.pushNamedAndRemoveUntil(
            context,
            Routes.dashboard,
            (route) => false,
            arguments: DashboardArgumentModel(
              onboardingState: dashboardArgumentModel.onboardingState,
            ).toMap(),
          );
        } else {
          Navigator.pop(context);
        }
      },
      child: Scaffold(

Issue:

However, the code using PopScope gives me the following error when I click on the back button:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: ‘package:flutter/src/widgets/navigator.dart’: Failed assertion: line 5238 pos 12: ‘!_debugLocked’: is not true.

I have tried

  • wrapping the Navigator.pop(context) in a WidgetsBinding.instance.addPostFrameCallback((_)
  • adding a Future.delayed() before Navigator.pop(context) but keep facing the same issue.

Request:

I would like to know what I’m doing wrong in my code which is preventing me from implementing the desired behaviour using PopScope and how to rectify the error.

2

Answers


  1. Chosen as BEST ANSWER

    Based on the answer given at: https://stackoverflow.com/a/77529346/19413610

    it turns out that I needed to return from the function if the boolean parameter to the onPopInvoked function returns true. Below is the functioning code:

    PopScope(
              onPopInvoked: (didPop) async {
                if (didPop) {
                  return;
                }
                if (hasProfilePicUpdated) {
                  Navigator.pushNamedAndRemoveUntil(
                    context,
                    Routes.dashboard,
                    (route) => false,
                    arguments: DashboardArgumentModel(
                      onboardingState: dashboardArgumentModel.onboardingState,
                    ).toMap(),
                  );
                } else {
                  Navigator.pop(context);
                }
              },
              child: Scaffold(
    

  2. You can use the SchedulerBinding.instance.addPostFrameCallback() method to delay the call to Navigator.pop() until after the current frame has been rendered.

    SchedulerBinding.instance.addPostFrameCallback((_) {
        Navigator.pop(context);
      });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search