Detect back button press while dialog is open in flutter
Asked Answered
R

8

71

I am creating an app in a flutter in which I need to display an alert dialog. And this is not a dismissible dialog. But when I press the back button on android it is getting dismissed. I have tried using WillPopScope widget to detect back press events. I am able to detect back button press using WillPopScope but this is not working while the dialog is open. Any suggestion and guide will be really helpful. Thanks.

Dialog creation snippet:

void buildMaterialDialog(
  String dialogTitle,
  String dialogContent,
  String negativeBtnText,
  String positiveBtnText,
  String positiveTextUri) {

showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return new AlertDialog(
        title: new Text(dialogTitle),
        content: new Text(dialogContent),
        actions: <Widget>[
          new FlatButton(
            onPressed: () {
              //Function called
              _updateDialogNegBtnClicked(isCancelable);
            },
            child: new Text(negativeBtnText),
          ),
          new FlatButton(
            onPressed: () => launch(positiveTextUri),
            child: new Text(positiveBtnText),
          ),
        ],
      );
    });}
Retinol answered 5/11, 2018 at 14:45 Comment(3)
Do you want to detect backpress or to prevent closing of dialog?Aran
I want to prevent dialog from closingRetinol
could you share the snippet @DurhamRetinol
D
204

Back button won't close the dialog.

showDialog(
  context: context,
  barrierDismissible: false,
  builder: (BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false, // False will prevent and true will allow to dismiss
      child: AlertDialog(
        title: Text('Title'),
        content: Text('This is Demo'),
        actions: <Widget>[
          FlatButton(
            onPressed: () => Navigator.pop(context),
            child: Text('Go Back'),
          ),
        ],
      ),
    );
  },
);
Durham answered 5/11, 2018 at 15:7 Comment(6)
thats great. But all this time I have been returning a Future inside the onWillPop, like onWillPop:(){return Future.value(false);} . never knew it could work without!Pinchbeck
or we can use '() async => false'Paiz
@MaciejStramski that's actually the preferred way. It saves me from suppressing warnings in my IDE regarding unfulfilled return type declarations (Future<Bool>).Beeline
if you already use WillPopScope(), barrierDismissible = false is no longer needed thoMemorialize
If the view on witch you open the dialog has WillPopScope already, it will trigger that too. I found this where people discuss it, but seems like there is no solution. github.com/flutter/flutter/issues/47088Poulard
I keep going back to this.. I'm so stoopid XDObryant
D
10

Guys! I'm from 2023) method WillPopScope is update:

PopScope(canPop: false, child: AlertDialog())
Deuno answered 17/12, 2023 at 15:2 Comment(0)
A
2

Because my reputation not enough to comment on the accepted answer, I want to give other alternative for onPressed: () {}. You can use onPressed: () => null. No warning will pop up.

Apure answered 13/8, 2020 at 14:15 Comment(0)
B
1

Three ways to stop dialog getting closed by Android Back Button

Option one:

           onWillPop: () {
                          return Future.value(false);
                        },

Option Two:

    onWillPop: () async {
                          return false;
                        },

Option Three:

 onWillPop: () {}, // This will give surpress warning, try to avoid this one.
Bilow answered 14/6, 2020 at 13:33 Comment(0)
D
1
 @override
      Widget build(BuildContext context) {
        return WillPopScope(
          onWillPop: _onBackPressed,
          child: Scaffold(
            
          ),
        );
      }
    
      Future<bool> _onBackPressed() async {
        return await showDialog(
            context: context, builder: (context) => ExitAppDialogBox());
      }
Directorial answered 11/11, 2021 at 16:4 Comment(0)
E
0

easy way

@override

Widget build(BuildContext context) {

return WillPopScope(

  onWillPop: () async{
    final value = await showDialog<bool>(
        context: context,
        builder: (context){
          return AlertDialog(
            title: Text("Alert"),
            content: Text("Do you want to Exit ?."),
            actions: [
              TextButton(onPressed: (){
                Navigator.of(context).pop(false);
              }, child: Text("No")),
              TextButton(onPressed: (){
                Navigator.of(context).pop(true);
              }, child: Text("Yes")),
            ],
          );
        });

    if(value != null){
      return Future.value(value);
    }else{
     return Future.value(false);
    }

  },
  child: Scaffold()

);

Embosom answered 19/12, 2023 at 3:42 Comment(0)
L
0

WillPopScope is deprecated. You need to use PopScope with callback:

    PopScope(
      canPop: false,
      onPopInvoked: (popped) {
        if (popped) return;

        // My variant - show the pop up dialog by leave attempt. 
        (state.isDrafted ? showExitPopup(context, builderCubit.saveDraftToDb) : Future.value(true))
            .then((pop) => (pop) ? Navigator.of(context).pop() : null);
      },
      child: child,
    );
Listed answered 27/4 at 7:19 Comment(0)
W
0

There was update to new major version, from now you can wrap your scaffold with PopScope widget like this:

PopScope(
      canPop: false, //THIS IS IMPORTANT
      onPopInvoked: (didPope) async {
        await showDialog<bool>(
          context: context,
          builder: (context) {
            return AlertDialog(
              content: Text('some question?'),
              actions: <Widget>[
                TextButton('cancelButton'),
                TextButton('confirmButton'),
              ],
            );
          },
        );
      },
      child: DefaultScaffold(...)
);
Wrapped answered 18/5 at 9:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.