a_dmitted
a_dmitted

Reputation: 103

Make showCupertinoModalPopup to return a value

Flutter reference documentation shows an example of using CupertinoPicker class wrapped by CupertinoModalPopupRoute popup Dialog: https://api.flutter.dev/flutter/cupertino/CupertinoPicker-class.html (dartpad snippet available)

The Dialog with a CupertinoPicker pops up, once a button is clicked. Button's onPressed calls:

  void _showDialog(Widget child) {
    showCupertinoModalPopup<void>(
        context: context,
        builder: (BuildContext context) => Container(
              // some UI setting omitted 
              child: SafeArea(
                top: false,
                child: child,
              ),
            ));
  }

where child is:

  CupertinoPicker(
    // some UI setting omitted 
    onSelectedItemChanged: (int selectedItem) {
      setState(() {
        _selectedFruit = selectedItem;
      });
    },
    children:
        List<Widget>.generate(_fruitNames.length, (int index) {
      return Center(
        child: Text(
          _fruitNames[index],
        ),
      );
    }),
  ),
    

Method showCupertinoModalPopup used to push a Dialog with a Picker just above the main page.

  1. Method's annotation mentions that "Content below the widget is dimmed with a [ModalBarrier]", and exactly ModalBarrier's handleDismiss method is called once user taps outside the Dialog's area, this leads to Navigator.pop being called, which pops the Dialog returning default void value (I cannot find a way to pass custom callback to the ModalBarrier)
  2. Again from the showCupertinoModalPopup's annotation: "Returns a Future that resolves to the value that was passed to [Navigator.pop] when the popup was closed."

So the question is, what is the right way (if any) to override Navigator.pop to make showCupertinoModalPopup return a value? I don't want to use Picker's onSelectedItemChanged as it constantly changes the state while user choses right value.

Instead I would use it like:

Future<void> _showDialog(Widget child) async {
    int? value = await showCupertinoModalPopup<int>(
        context: context,
        builder: (BuildContext context) => Container(
             //omitted
              child: SafeArea(
                top: false,
                child: child,
              ),
            ));

    setState(() {
      Provider.of<FruitsController>(context, listen: false).currentFruit = value;
    });
  }

I would appreciate your help.

Upvotes: 2

Views: 4613

Answers (1)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63549

Yes you can create a button to pop from showCupertinoModalPopup.

  Future<void> _showDialog() async {
    int? value = await showCupertinoModalPopup<int>(
      context: context,
      builder: (BuildContext context) => Column(
        children: [
          ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop(-2); //pasing value on pop is -2
              },
              child: Text("Close ")),
          Container(
            child: SafeArea(
              top: false,
              child: CupertinoPicker(
                onSelectedItemChanged: (int selectedItem) {
                  _selectedFruit = _fruitNames[selectedItem];
                },
                itemExtent: 33,
                children:
                    List<Widget>.generate(_fruitNames.length, (int index) {
                  return Center(
                    child: Text(
                      _fruitNames[index],
                    ),
                  );
                }),
              ),
            ),
          ),
        ],
      ),
    );

    print(value);
  }

Upvotes: 1

Related Questions