ahmed elkhyary
ahmed elkhyary

Reputation: 1341

WillPopScope is deprecated in Flutter

'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;
  },
)

Upvotes: 48

Views: 70993

Answers (15)

sajid
sajid

Reputation: 215

it's working

Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: AppColors.page_bg_color,
      body: PopScope(
        canPop: false,
        onPopInvokedWithResult: (didPop, result) {
          if(didPop) {
            return;
          }
          callBackFunction(context);
        },
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
              //widget
          ],
        ),
      ),
    );
  }

void callBackFunction(BuildContext context) {
   // handle back button functionality here,

  }

Upvotes: 0

Manish
Manish

Reputation: 835

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();
  }
 },
)

Edit

onPopInvoked is Deprecated now, use onPopInvokedWithResult instead.

PopScope(
 canPop: false,
 onPopInvokedWithResult: (didPop, result) async {
  if (didPop) {
    return;
  }
  final navigator = Navigator.of(context);
  bool value = await someFunction();
  if (value) {
    navigator.pop(result);
  }
 },
)

If you call Navigator.maybePop(context, someData) you will get someData in result

Upvotes: 53

Sagar Sharma
Sagar Sharma

Reputation: 581

onPopInvoked Deprecated in Favor of onPopInvokedWithResult

    // Old implementation with PopScope
   PopScope(
      canPop: false,
      onPopInvoked : (didPop){
      // logic
      },
   )
    
    // New implementation with PopScope
    PopScope(
      canPop: false,
      onPopInvokedWithResult: (context, result) {
        // Handle back navigation
      },
      child: MyWidget(),
    );

Upvotes: 2

Ahmed Ibrahim Ghnnam
Ahmed Ibrahim Ghnnam

Reputation: 59

WillPopScope Deprecated in Favor of PopScope

As of the latest Flutter updates, the WillPopScope widget has been deprecated and replaced by PopScope. If you’re maintaining legacy code or starting a new project, it's important to update your code to use PopScope instead.

// Old implementation with WillPopScope
WillPopScope(
  onWillPop: () async {
    // Handle back navigation
    return true;
  },
  child: MyWidget(),
);

// New implementation with PopScope
PopScope(
  onPopInvokedWithResult: (context, result) {
    // Handle back navigation
  },
  child: MyWidget(),
);

onPopInvoked Deprecated in Favor of onPopInvokedWithResult

Similarly, the onPopInvoked callback has been deprecated in favor of onPopInvokedWithResult. This new callback provides the context and the result of the pop event, giving you more flexibility in handling back navigation.

Updating your code to reflect these changes will ensure compatibility with future Flutter releases and take advantage of the latest improvements in navigation handling.

Upvotes: 5

Mikhail Goulding
Mikhail Goulding

Reputation: 63

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;
    }
  }

Upvotes: 6

Himanshu M. Dave
Himanshu M. Dave

Reputation: 1

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}

Upvotes: 0

Al Hasan
Al Hasan

Reputation: 152

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.

Upvotes: 0

NineO
NineO

Reputation: 1

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: ...
)

Upvotes: 0

Abdul Salam
Abdul Salam

Reputation: 56

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;
  },
)

Upvotes: 0

Desarrollo Goclases
Desarrollo Goclases

Reputation: 1

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:

Upvotes: 0

ahmed elkhyary
ahmed elkhyary

Reputation: 1341

Solved

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

/// NEW CODE
PopScope(
  canPop: false,
  onPopInvoked : (didPop){
   // logic
  },
)

Upvotes: 65

Mehmet G&#252;ler
Mehmet G&#252;ler

Reputation: 48

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)

Upvotes: 2

Philipp
Philipp

Reputation: 3

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,
    );
  }
}

Upvotes: 0

Apurv Thakkar
Apurv Thakkar

Reputation: 10228

PopScope(
  canPop: false,  //It should be false to work
  onPopInvoked : (didPop) {
   if (didPop) {
      return;
    }
    Get.back(); //Here this temporary, you can change this line
  },
)

Upvotes: 8

MUHINDO
MUHINDO

Reputation: 1221

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'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Upvotes: 0

Related Questions