我正在通过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")
),
]),
);
});
答案 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),
);
},
);
});
}
输出:
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"),
),
),
);
}
输出:
答案 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),
);
}
}
答案 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();
}
以这种方式,就像我的小部件层次结构一样;如果用户点击底部导航栏,用户可以更改当前页面,我正在关闭当前底部工作表。
如果用户自己关闭底部表单,对于我们的动态控制器,我们可以关闭控制器并将其分配给空值。这样,我们就可以知道底页是否存在。