Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: CupertinoPicker BottomSheet listener for onClose?

I'm looking through the Flutter Gallery for the code related to the CupertinoPicker.

Here is the relevant code extract:

        child: new GestureDetector(
          // Blocks taps from propagating to the modal sheet and popping.
//          onTap: () { },
          child: new SafeArea(
            child: new CupertinoPicker(
              scrollController: scrollController,
              itemExtent: _kPickerItemHeight,
              backgroundColor: CupertinoColors.white,
              onSelectedItemChanged: (int index) {
                setState(() {
                  print(_selectedItemIndex);
                  _selectedItemIndex = index;
                });
              },
              children: new List<Widget>.generate(coolColorNames.length, (int index) {
                return new Center(child:
                  new Text(coolColorNames[index]),
                );
              }),
            ),
          ),
        ),

Now, I need a callback / listener for when the CupertinoPicker closes, in other words, when the user has made his selection and his selection is final, I need to know what his final selection is.

The use case here is that I want to make an api callback based on his final selection when the bottomsheet closes.

At the moment, I can only get the values as the picker is spun by the user as there is only a callback for onSelectedItemChanged. See gif below.

enter image description here

I see the BottomSheet widget has an onClosing callback: https://docs.flutter.io/flutter/material/BottomSheet-class.html

But I'm confused as to how I can get an instance of it to use as the Flutter Gallery sample is calling the bottomsheet using the following code and there is no method to get the bottomsheet from the code:

      new GestureDetector(
        onTap: () async {
          await showModalBottomSheet<void>(
            context: context,
            builder: (BuildContext context) {
              return _buildBottomPicker();
            },
          );
        },
        child: _buildMenu(),
      ),

Does anyone know how I can get the callback listener for this?

EDIT - Based on Remi's solution, I have added the Navigator.of(context).pop(value) code within the onTap call back. However, the CupertinoPicker is not persistent so if the user touches outside the picker, the picker dismisses itself and a null value will be returned:

  Widget _buildBottomPicker() {
    final FixedExtentScrollController scrollController =
        new FixedExtentScrollController(initialItem: _selectedItemIndex);

    return new Container(
      height: _kPickerSheetHeight,
      color: CupertinoColors.white,
      child: new DefaultTextStyle(
        style: const TextStyle(
          color: CupertinoColors.black,
          fontSize: 22.0,
        ),
        child: new GestureDetector(
          // Blocks taps from propagating to the modal sheet and popping.
          onTap: () { Navigator.of(context).pop(_selectedItemIndex);},
          child: new SafeArea(
            child: new CupertinoPicker(
              scrollController: scrollController,
              itemExtent: _kPickerItemHeight,
              backgroundColor: CupertinoColors.white,
              onSelectedItemChanged: (int index) {
                setState(() {
//                  print(_selectedItemIndex);
//                  Navigator.of(context).pop(index);
                  _selectedItemIndex = index;
                });
              },
              children: new List<Widget>.generate(coolColorNames.length, (int index) {
                return new Center(child:
                  new Text(coolColorNames[index]),
                );
              }),
            ),
          ),
        ),
      ),
    );
  }
like image 263
Simon Avatar asked Apr 17 '18 09:04

Simon


2 Answers

It's actually much simpler than what you thought.

showDialog and it's counterparts (including showModalBottomSheet) returns a Future that contains the result. So you can do the following :

final selectedId = await showModalBottomSheet<int>(...);

The only requirement is that when poping your modal/dialog/route/whatever, you do Navigator.of(context).pop(value) to send that value.

like image 108
Rémi Rousselet Avatar answered Nov 15 '22 10:11

Rémi Rousselet


like this:

future.whenComplete(() => requestRefresh());
like image 23
wslaimin Avatar answered Nov 15 '22 10:11

wslaimin