Flutter WillPopScope with AlertDialog migration to null-safety

2,142

Solution 1

I guess easiest would be:

Future<bool> _onBackPressed(BuildContext context) async {
    ...
    return (await showDialog(..)) ?? false // if dialog returns null, return false instead
    ...

or

bool? dialogResp = await showDialog(...);
if(dialogResp !=) 
   return dialogResp; 
else 
   return false;

or

Future<bool> _onBackPressed(BuildContext context) async {
    ...
    return showDialog(..).then((x) => x ?? false)
    ...

Solution 2

Since showDialog can return null, we can use a ?? operator to return another value when showDialog returns null. In this case, false:

  Future<bool> _onWillPop() async {
    return (await showDialog(
      context: context,
      builder: (context) => new AlertDialog(),
    )) ?? false;
  }

Then use this on WillPopScope:

    return WillPopScope(
      onWillPop: _onWillPop,
      child: Scaffold(
Share:
2,142
duffy
Author by

duffy

Updated on December 29, 2022

Comments

  • duffy
    duffy over 1 year

    I have recently migrated my Flutter app to null-safety but WillPopScope in combination with AlertDialog causes a problem. WillPopScope expects Future<bool> but showDialog returns Future<bool?> and I can't figure out how to cast one onto the other.

    Widget _buildBody(BuildContext context) {
      return WillPopScope(
        onWillPop: (() => _onBackPressed(context)) as Future<bool> Function(),
        child: new Container([...]),
      );
    }
    
    // this should return a Future<bool> but showDialog doesn't allow that
    Future<bool?> _onBackPressed(BuildContext context) async {
      if (someCondition) {
        // showDialog returns a Future<T?> 
        return showDialog(
          context: context,
          builder: (context) => new AlertDialog(
            [...]
            actions: <Widget>[
              new TextButton(
                child: Text("cancel",
                onPressed: () => Navigator.of(context).pop(false),
              ),
              new TextButton(
                child: Text("discard",
                onPressed: () => Navigator.of(context).pop(true),
              ),
            ],
        ));
      } else {
        return true;
      }
    }
    

    The cast (() => _onBackPressed(context)) as Future<bool> Function() in onWillPop as shown in this sample is not working.

    The following _CastError was thrown building Builder(dirty):
    type '() => Future<bool?>' is not a subtype of type '() => Future<bool>' in type cast
    

    Any idea how I can catch the null value returned by showDialog and make willPopScope happy again?

  • duffy
    duffy about 3 years
    I wish I could mark more than one answer as correct. Thank you for your super speedy and helpful response, even though Nuts beat you by 1 minute!!!