WillPopScope is deprecated in Flutter
Asked Answered
S

12

34

'WillPopScope' is deprecated and shouldn't be used. Use PopScope instead. This feature was deprecated after v3.12.0-1.0.pre

WillPopScope(
  onWillPop: () async {
    // your logic        
    return false;
  },
)
Splint answered 22/11, 2023 at 12:21 Comment(3)
Please read at docs.flutter.dev/release/breaking-changes/…Coeternal
Use PopScope - aravi.me/blog/willpopscope-is-now-popscope-in-flutterAmbrosial
You can watch this to gain more insight - youtube.com/watch?v=W9ihZAFBjpQDolt
S
50

Solved

replace old widget from WillPopScope to PopScope new widget check below code

/// NEW CODE
PopScope(
  canPop: false,
  onPopInvoked : (didPop){
   // logic
  },
)
Splint answered 23/11, 2023 at 10:16 Comment(3)
that doesn't answer at all how the new class works. api.flutter.dev/flutter/widgets/PopScope-class.htmlHibernicism
And make canPop: false, as Apurv Thakkar answer.Macleod
to prevent the pop, you can set canPop to false and handle the pop manually by using onPopInvoked and use Navigator.pop(context)Tamarah
L
30

You can use it like this.

PopScope(
 canPop: false,
 onPopInvoked: (didPop) async {
  if (didPop) {
    return;
  }
  final navigator = Navigator.of(context);
  bool value = await someFunction();
  if (value) {
    navigator.pop();
  }
},
Leavening answered 11/12, 2023 at 18:48 Comment(2)
``` if (didPop) { return; }``` is a dead code, the didPop only return true when the route successfully popped. while we set canPop to false, there's no chance didPop will be true if you want to prevent the pop, you can set canPop to false and handle the pop manually by using onPopInvokedTamarah
@Tamarah In the case of popUntil / pushAndRemoveUntil etc.. it will give you a true value, even if you have set canPop:falseLeavening
S
8
PopScope(
  canPop: false,  //It should be false to work
  onPopInvoked : (didPop) {
   if (didPop) {
      return;
    }
    Get.back(); //Here this temporary, you can change this line
  },
)
Storyteller answered 3/1 at 17:27 Comment(0)
F
2

You can try something like this:

PopScope(
      canPop: canPop,
      onPopInvoked: (bool value) {
        setState(() {
          canPop= !value;
        });

        if (canPop) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text("Click once more to go back"),
              duration: Duration(milliseconds: 1500),
            ),
          );
        }
      },
      child:child)
Frit answered 31/1 at 19:22 Comment(0)
T
1

This documentation mentions how to migrate from WillPopScope to PopScope:

Migrating from WillPopScope to PopScope

Before Migration:

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        // your logic
        return false;
      },
      child: Scaffold(...),
    );
  }

After Migration:

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: customLogic(),
      child: Scaffold(...),
    );
  }

  bool customLogic() {
    {
      // your logic
      return false;
    }
  }
Templia answered 11/7 at 14:35 Comment(0)
R
0

Here is a solution with example

import 'package:flutter/material.dart';

void main() => runApp(const NavigatorPopHandlerApp());

class NavigatorPopHandlerApp extends StatelessWidget {
  const NavigatorPopHandlerApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/home',
      routes: <String, WidgetBuilder>{
        '/home': (BuildContext context) => const _HomePage(),
        '/two': (BuildContext context) => const _PageTwo(),
      },
    );
  }
}

class _HomePage extends StatefulWidget {
  const _HomePage();

  @override
  State<_HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<_HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Page One'),
            TextButton(
              onPressed: () {
                Navigator.of(context).pushNamed('/two');
              },
              child: const Text('Next page'),
            ),
          ],
        ),
      ),
    );
  }
}

class _PageTwo extends StatefulWidget {
  const _PageTwo();

  @override
  State<_PageTwo> createState() => _PageTwoState();
}

class _PageTwoState extends State<_PageTwo> {
  void _showBackDialog() {
    showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Are you sure?'),
          content: const Text(
            'Are you sure you want to leave this page?',
          ),
          actions: <Widget>[
            TextButton(
              style: TextButton.styleFrom(
                textStyle: Theme.of(context).textTheme.labelLarge,
              ),
              child: const Text('Nevermind'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            TextButton(
              style: TextButton.styleFrom(
                textStyle: Theme.of(context).textTheme.labelLarge,
              ),
              child: const Text('Leave'),
              onPressed: () {
                Navigator.pop(context);
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Page Two'),
            PopScope(
              canPop: false,
              onPopInvoked: (bool didPop) {
                if (didPop) {
                  return;
                }
                _showBackDialog();
              },
              child: TextButton(
                onPressed: () {
                  _showBackDialog();
                },
                child: const Text('Go back'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Roberts answered 7/12, 2023 at 13:29 Comment(2)
this is a copy paste of api.flutter.dev/flutter/widgets/PopScope-class.htmlHibernicism
I am just posting the credits for the real source, for whoever may need the complete context for further details.Hibernicism
L
0

This is my current working solution: You can wrap it around your screen in the router and it redirects to your home screen or it shows the snackbar with then closing the app after another press on the go back button.

class GoBackOrCloseOnConfirmationState
    extends State<GoBackOrCloseOnConfirmation> {
  DateTime? currentBackPressTime;
  bool allowPop = false;

  bool closeOnConfirm() {
    DateTime now = DateTime.now();
    if (currentBackPressTime == null ||
        now.difference(currentBackPressTime!) > const Duration(seconds: 4)) {
      currentBackPressTime = now;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          behavior: SnackBarBehavior.floating,
          content: Center(child: Text('Drücke erneut um die App zu schließen')),
          duration: Duration(seconds: 4),
        ),
      );
      return false;
    }
    currentBackPressTime = null;
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvoked: (bool didPop) => {
        widget.closeAppOnConfirmation
            ? closeOnConfirm()
                ? SystemNavigator.pop()
                : null
            : context.go('/')
      },
      child: widget.child,
    );
  }
}
Lindo answered 16/1 at 17:11 Comment(1)
Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?Hiller
I
0
Future<bool> _onback(BuildContext context) async {
bool? exitApp = await showDialog(
  context: context,
  builder: ((context) {
    return AlertDialog(
      title: const Text('¿Quieres salir?',
          style: TextStyle(
            fontSize: 15,
          )),
      actions: [
        TextButton(
            onPressed: () {
              Navigator.of(context).pop(false);
            },
            child: const Text('No')),
        TextButton(
            onPressed: () {
              _flutterRadioPlayer.pause();
              _flutterRadioPlayer.stop();
              //exit(0);
              Navigator.of(context).pop(true);
            },
            child: const Text('Si'))
      ],
    );
  }),
);

return exitApp ?? false;
}

PopScope(
  canPop: false,
  onPopInvoked: (didPop) async {
    debugPrint("didPop1: $didPop");
    if (didPop) {
      return;
    }
    final bool shouldPop = await _onback(context);
    if (shouldPop) {
      SystemNavigator.pop();
    }
  },
  child:
Ionogen answered 1/2 at 20:22 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Yokel
R
0

If you're dealing with PopScope and flutter_inappwebview, here's a solution to help you out.

PopScope(
  canPop: false,
  onPopInvoked: (didPop) async {
    await webviewController.goBack();
  },
  child: ...
)
Robbie answered 10/5 at 11:1 Comment(0)
S
0

Flutter's recent updates have deprecated the 'WillPopScope' widget in favor of 'PopScope.' This means that the 'WillPopScope' widget, previously used for handling back button presses, is no longer supported and should be replaced with 'PopScope.' Make sure to update your code accordingly to ensure compatibility with the latest versions of Flutter.

PopScope(
  onPop: () async {
    // your logic        
    return false;
  },
)
Spoonbill answered 10/5 at 11:5 Comment(0)
L
0

Previously my flutter code block:

@override
Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () async {
      await _stop(); // Stop the speech when the back button is pressed
      return true;
    },
        child: Scaffold (...),
    );
  }

The updated flutter code block now:

enter image description here

which is working fine without any warning and errors.

Lillis answered 29/5 at 6:49 Comment(0)
T
0

you can use PopScope instead of using willPopScope, Here is my code with the example

first you have to the create a future class to design your alert dialog, in my case, the code is

Future<bool> _showExitConfirmationDialog(BuildContext context) async {
    return (await showDialog(
          context: context,
          builder: (context) => AlertDialog(
            backgroundColor: dropDownColor,
            elevation: 10,
            shadowColor: primaryGradient,
            title: MyText(
              color: screenText,
              text: 'exit',
              multilanguage: true,
              fontsizeNormal: 20,
              fontweight: FontWeight.w900,
            ),
            content: MyText(
              color: screenText,
              text: 'sure',
              multilanguage: true,
              fontsizeNormal: 16,
              fontweight: FontWeight.bold,
            ),
            actions: <Widget>[
              ElevatedButton(
                child: MyText(
                  color: txtdecoColor,
                  text: 'no',
                  multilanguage: true,
                ),
                onPressed: () => Navigator.of(context).pop(false),
              ),
              ElevatedButton(
                child: MyText(
                  color: txtdecoColor,
                  text: 'yes',
                  multilanguage: true,
                ),
                onPressed: () => SystemNavigator.pop(),
              ),
            ],
          ),
        )) ??
        false;
  }

I have used custom text widget named MyText, you can use the simple Text widget.

After creating the future class, you have to wrap your scaffold with the PopScope widget, and pass the canPop and onPopInvoked.

as per my code, it goes like this:

@override
  Widget build(BuildContext context) {
    return PopScope(
          canPop: false,
          onPopInvoked: (bool didPop) async {
            if (didPop) {
              return;
            }
            final bool shouldPop = await _showExitConfirmationDialog(context);
            if (context.mounted && shouldPop) {
              Navigator.pop(context);
            }
          },
          child: Scaffold( //Your body code),);//ending PopScope}
Trite answered 14/6 at 6:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.