Flutter:onClose的CupertinoPicker BottomSheet监听器?

时间:2018-04-17 09:42:06

标签: flutter bottom-sheet cupertinopicker

我正在通过Flutter Gallery查看与CupertinoPicker相关的代码。

以下是相关代码摘录:

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

现在,当CupertinoPicker关闭时,我需要一个回调/监听器,换句话说,当用户做出选择并且他的选择是最终的时,我需要知道他的最终选择是什么。

这里的用例是我想在底片关闭时根据他的最终选择进行api回调。

目前,由于只有onSelectedItemChanged的回调,我只能获取用户旋转选择器的值。见下面的gif。

enter image description here

我看到BottomSheet小部件有一个onClosing回调:https://docs.flutter.io/flutter/material/BottomSheet-class.html

但是我很困惑如何获得它的实例,因为Flutter Gallery样本使用以下代码调用底层,并且没有方法从代码中获取底层:

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

有谁知道如何获得回调侦听器?

编辑 - 基于Remi的解决方案,我在onTap回调中添加了Navigator.of(context).pop(value)代码。但是,CupertinoPicker不是持久的,因此如果用户触摸选择器外部,选择器会自行解除并返回空值:

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

4 个答案:

答案 0 :(得分:7)

它实际上比你想象的要简单得多。

showDialog及其对应方(包括showModalBottomSheet)会返回包含结果的Future。所以你可以做到以下几点:

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

唯一的要求是,当弹出你的模态/对话框/路线/其他时,你会Navigator.of(context).pop(value)发送该值。

答案 1 :(得分:0)

就像前面的回答一样,所需的值以Future的形式返回给您。虽然这是事实,但对我而言,如何实现它并不明显。就我而言,我想按同一屏幕上的类别列表过滤待办事项列表。因此,通过使用onSelectedItemChanged返回的int键,我可以像这样进行过滤...

{
    "text": "New comic book alert!",
    "attachments": [
        {
            "title": "The Further Adventures of Slackbot",
            "fields": [
                {
                    "title": "Volume",
                    "value": "1",
                    "short": true
                },
                {
                    "title": "Issue",
                    "value": "3",
            "short": true
                }
            ],
            "author_name": "Stanford S. Strickland",
            "author_icon": "http://a.slack-edge.com/7f18https://a.slack-edge.com/a8304/img/api/homepage_custom_integrations-2x.png",
            "image_url": "http://i.imgur.com/OJkaVOI.jpg?1"
        },
        {
            "title": "Synopsis",
            "text": "After @episod pushed exciting changes to a devious new branch back in Issue 1, Slackbot notifies @don about an unexpected deploy..."
        },
        {
            "fallback": "Would you recommend it to customers?",
            "title": "Would you recommend it to customers?",
            "callback_id": "comic_1234_xyz",
            "color": "#3AA3E3",
            "attachment_type": "default",
            "actions": [
                {
                    "name": "recommend",
                    "text": "Recommend",
                    "type": "button",
                    "value": "recommend"
                },
                {
                    "name": "no",
                    "text": "No",
                    "type": "button",
                    "value": "bad"
                }
            ]
        }
    ]
}

您无需在showCupertinoModalPopup或类似的内容上设置决赛...

Widget _buildCategoryPicker(BuildContext context, _todoBloc) {
final FixedExtentScrollController scrollController =
    FixedExtentScrollController(initialItem: _selectedIndex);

return GestureDetector(
  onTap: () async {
    await showCupertinoModalPopup<String>(
      context: context,
      builder: (BuildContext context) {
        return _buildBottomPicker(    
          CupertinoPicker(
            (...)
            onSelectedItemChanged: (int index) {
              setState(() => _selectedIndex = index);
            },
            children: (...),
          ), // CupertinoPicker
        );
      },
    ); // await showCupertinoModalPopup

   // Filters the todoList.
    _todoBloc.filter.add(categories[_selectedIndex]);
   },
   child: _buildMenu(
     ...
   ),
 );
}

答案 2 :(得分:0)

像这样:

future.whenComplete(() => requestRefresh());

答案 3 :(得分:0)

showModalBottomSheet(
  context: context,
  builder: (_) {
    return GestureDetector(
      onTap: () => Navigator.of(context).pop(), // closing showModalBottomSheet
      child: FlutterLogo(size: 200),
    );
  },
 );