以编程方式关闭模态底部图表

时间:2018-04-11 15:20:39

标签: dart flutter

我正在通过showModalBottomSheet<Null>()显示一个BottomSheet,并在几个小部件中显示一个GestureDetector。 我希望看到BottomSheet不仅通过触摸它而且还在内部的GestureDetector的onTap事件之后关闭。但是,似乎GestureDetector没有转发触摸事件。

所以我想知道,有没有办法以编程方式触发ModalBottomSheet的关闭或告诉GestureDetector转发触摸事件?

更新(2018-04-12):

遵循代码段以便更好地理解。问题是当点击“Item 1”或“Item 2”时,ModalBottomSheet没有关闭。

showModalBottomSheet<Null>(context: context, builder: (BuildContext context)
{
  return new SingleChildScrollView(child:
    new Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
      new GestureDetector(onTap: () { doSomething(); }, child:
        new Text("Item 1")
      ),
      new GestureDetector(onTap: () { doSomething(); }, child:
        new Text("Item 2")
      ),
    ]),
  );
});

7 个答案:

答案 0 :(得分:30)

我无法找到如何传递由GestureDetector捕获的事件。但是,以编程方式关闭ModalBottomSheet是通过

完成的
Navigator.pop(context);

所以我只是在GestureDetector的onTap回调函数中调用pop函数。

showModalBottomSheet<Null>(context: context, builder: (BuildContext context)
{
  return new SingleChildScrollView(child:
    new Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
      new GestureDetector(onTap: () {
          Navigator.pop(context);
          doSomething();
        }, child:
        new Text("Item 1")
      ),
      new GestureDetector(onTap: () {
          Navigator.pop(context);
          doSomething();
        }, child:
        new Text("Item 2")
      ),
    ]),
  );
});

答案 1 :(得分:7)

通常有两种类型的底页。

(I)showModalBottomSheet //像Dialog一样工作,而不是Scaffold的一部分

(II)showBottomSheet //这是Scaffold

的一部分

显示和隐藏showModalBottomSheet

此代码显示底部工作表,并在点击FlutterLogo

时将其隐藏
@override
void initState() {
  super.initState();
  Timer.run(() {
    showModalBottomSheet(
      context: context,
      builder: (_) {
        return GestureDetector(
          onTap: () => Navigator.of(context).pop(), // closing showModalBottomSheet
          child: FlutterLogo(size: 200),
        );
      },
    );
  });
}

输出:

enter image description here


显示和隐藏showBottomSheet

此代码显示一个按钮,它将打开和关闭底部的工作表。

PersistentBottomSheetController _controller;
GlobalKey<ScaffoldState> _key = GlobalKey();
bool _open = false;

@override
Widget build(BuildContext context) {
  return Scaffold(
    key: _key,
    body: Center(
      child: RaisedButton(
        onPressed: () {
          if (!_open) {
            _controller = _key.currentState.showBottomSheet(
              (_) => SizedBox(
                child: FlutterLogo(size: 200),
                width: double.maxFinite,
              ),
            );
          } else {
            _controller.close();
          }
          setState(() => _open = !_open);
        },
        child: Text(_open ? "Close" : "Open"),
      ),
    ),
  );
}

输出:

enter image description here

答案 2 :(得分:4)

在颤动中显示和隐藏底部工作表:

 showModalBottomSheet(
    context: context,
    builder: (bCtx) {
      return GestureDetector(
        behavior: HitTestBehavior.opaque,
        child: Container(height: 300, child: Text('Bottom sheet widget'),),
        onTap: () {
          Navigator.of(context).pop();
        },
      );
    },
  );

答案 3 :(得分:3)

代码中的解决方法是像这样包装底部的小部件。底部工作表中的按钮仍然有效:

GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () =>  Navigator.pop(context),
      child: <existing bottom sheet widget>
)

答案 4 :(得分:3)

如果您的模态表没有下降并直接返回上一页,那么您可以使用{useRootNavigator:true},然后使用另一个函数中的Navigator.pop(context);。它只会隐藏模态表,而不是转到上一页。

答案 5 :(得分:1)

class _FABState extends State<FAB> {
  bool isOpen = false;

  var bottomSheetController;

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: () {
        setState(() {
          isOpen = !isOpen;
        });
        print('tapped on the bottom sheet');
        if(isOpen) {
          bottomSheetController = showBottomSheet(
              backgroundColor: Colors.transparent,
              context: context,
              builder: (ctx) {
                return ClipRRect(
                  borderRadius: BorderRadius.only(
                    topRight: Radius.circular(20),
                    topLeft: Radius.circular(20),
                  ),
                  child: Container(
                    height: 150,
                    color: Colors.black,
                    child: TextField()
                  ),
                );
              });
          bottomSheetController.closed.then((value) {
            setState(() {
              isOpen = !isOpen;
            });
          });
        } else {
          Navigator.of(context).pop();
          setState(() {
            isOpen = !isOpen;
          });
        }
      },
      child: isOpen?Icon(Icons.arrow_downward):Icon(Icons.arrow_upward),
    );
  }
}

Video Representing the bottom sheet

答案 6 :(得分:0)

如果您使用带有脚手架键和持久性底部面板控制器的底部面板,我的方式就像;

final scaffoldState = GlobalKey<ScaffoldState>();
dynamic controller;
        
if(controller!=null){
   controller as PersistentBottomSheetController).close();
   controller=null;
}
    
override
void dispose() {
   if(controller!=null){
      controller as PersistentBottomSheetController).close();
   }
   super.dispose();
}

以这种方式,就像我的小部件层次结构一样;如果用户点击底部导航栏,用户可以更改当前页面,我正在关闭当前底部工作表。

如果用户自己关闭底部表单,对于我们的动态控制器,我们可以关闭控制器并将其分配给空值。这样,我们就可以知道底页是否存在。