【问题标题】:Flutter: CupertinoPicker BottomSheet listener for onClose?Flutter:用于 onClose 的 CupertinoPicker BottomSheet 监听器?
【发布时间】:2018-04-17 09:42:06
【问题描述】:

我正在 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 关闭时,我需要一个回调/监听器,换句话说,当用户做出他的选择并且他的选择是最终的时,我需要知道他的最终选择是什么。

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

目前,我只能在选择器由用户旋转时获取值,因为只有 onSelectedItemChanged 的​​回调。请参阅下面的 gif。

我看到 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 不是持久的,因此如果用户在选取器外部触摸,选取器会自行关闭并返回 null 值:

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

【问题讨论】:

  • 要在选择器之外捕捉触摸,请使用WillPopScope

标签: flutter bottom-sheet cupertinopicker


【解决方案1】:

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

showDialog 及其对应项(包括showModalBottomSheet)返回包含结果的Future。因此,您可以执行以下操作:

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

唯一的要求是当你弹出你的模态/对话框/路由/任何东西时,你做Navigator.of(context).pop(value)来发送那个值。

【讨论】:

  • H Remi,你能告诉我把 Navigator.of(context).pop(value) 代码放在哪里吗?我只希望选择器出现,用户必须选择值,然后当用户关闭选择器时,必须确定最终的 selectedId。我没有离开页面,所以我很困惑我必须把导航器放在哪里。
  • _buildBottomPicker 内部某处。但我没有那个部分
  • 模式/对话框是显示在其他路线顶部的路线。所以它们也被Navigator 实例化/删除
  • 我已将代码添加到问题中,并将代码的 Navigator 部分添加到 onTap 方法,但这需要用户点击他想从选择器中选择的项目,而导航器不会如果用户滚动选择器以进行选择,然后通过单击屏幕灰色区域中的选择器外部来关闭选择器,则调用它。当用户在触摸屏幕的灰色部分时关闭选择器时,有没有办法调用导航器?
  • 通常用户希望在单击阴影时取消他的操作,因此您可能需要重新考虑。但是你可以使用WillPopScope 来进行onWillPop 回调,虽然不是最优的
【解决方案2】:

像这样:

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

【讨论】:

    【解决方案3】:

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

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

    你不需要在你的 showCupertinoModalPopup 或类似的东西上设置决赛...

    final selectedId = await showCupertinoModalPopup<String>(...);
    

    【讨论】:

      【解决方案4】:
      showModalBottomSheet(
        context: context,
        builder: (_) {
          return GestureDetector(
            onTap: () => Navigator.of(context).pop(), // closing showModalBottomSheet
            child: FlutterLogo(size: 200),
          );
        },
       );
      

      【讨论】:

      • 请至少提供有关代码的基本信息,它是如何工作的,它是如何解决问题的......
      猜你喜欢
      • 1970-01-01
      • 2019-12-07
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 2022-06-11
      • 2021-12-14
      • 2021-05-28
      • 1970-01-01
      相关资源
      最近更新 更多