在颤振中可编程关闭模态底板

我正在通过 showModalBottomSheet<Null>()显示一个 BottomSheet,并在几个具有 GestureDetector 的小部件中显示它。 I would like to see the BottomSheet closed not only by touching outside it but also after an onTap event of a GestureDetector inside. However, it seems the GestureDetector is not forwarding the touch event.

所以我想知道,是否有一种方法可以通过编程触发 ModalBottomsheet 的关闭,或者告诉 GestureDetector 转发触摸事件?

更新(2018-04-12) :

下面是一个代码片段,以便更好地理解。问题在于,当点击“ Item1”或“ Item2”时,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")
),
]),
);
});
118929 次浏览

以编程方式关闭 ModalBottomsheet 是通过

Navigator.pop(context);

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

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

简短的回答:

使用以下任何一项:

Navigator.pop(context);
Navigator.of(context).pop();

长话短说:

一般有两种类型的底板。

  1. 类似于 Dialog,而不是 Scaffold的一部分

  2. showBottomSheet = > Scaffold的一部分,这是持久的。


1. 显示和隐藏 showModalBottomSheet

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

@override
void initState() {
super.initState();
Future(() {
showModalBottomSheet(
context: context,
builder: (_) {
return GestureDetector(
onTap: () => Navigator.of(context).pop(), // Closing the sheet.
child: FlutterLogo(size: 200),
);
},
);
});
}

产出:

enter image description here


2. 显示和隐藏 showBottomSheet

This code shows a button, which will open and close the bottom sheet.

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

@override
Widget build(BuildContext context) {
return Scaffold(
key: _key,
body: Center(
child: ElevatedButton(
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"),
),
),
);
}

Output:

enter image description here

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

在颤动中显示和隐藏底片:

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

如果您的模态表没有下降并直接返回到前一页,那么您可以使用 {useRootNavigator:true},然后使用来自其他函数的 Navigator.pop(context);。它将只隐藏模式表,而不是采取到上一页。

如果你是使用底板与脚手架键和持久性底板控制器我的方式是喜欢;

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


这样,对于像我的小部件层次结构; 如果用户单击底部导航栏,用户可以更改当前页面,我关闭当前底部工作表。

如果用户自己关闭底部工作表,对于我们的动态控制器,我们可以关闭控制器并将其赋值为空值。这样我们就可以知道底纸是否存在。

一旦您的代码完成了预期的任务,您可以在结尾添加 Navigator.of(context, rootNavigator: true).pop();,以便模态关闭