我有一个Stack,可以在其中拖动几个小部件。另外,堆栈所在的容器还具有一个GestureDetector,可在onTapDown和onTapUp上触发。我希望仅当用户在堆栈中的窗口小部件外部点击时才触发那些onTap事件。我尝试了以下代码:
class Gestures extends StatefulWidget {
@override
State<StatefulWidget> createState() => _GesturesState();
}
class _GesturesState extends State<Gestures> {
Color background;
Offset pos;
@override
void initState() {
super.initState();
pos = Offset(10.0, 10.0);
}
@override
Widget build(BuildContext context) => GestureDetector(
onTapDown: (_) => setState(() => background = Colors.green),
onTapUp: (_) => setState(() => background = Colors.grey),
onTapCancel: () => setState(() => background = Colors.grey),
child: Container(
color: background,
child: Stack(
children: <Widget>[
Positioned(
top: pos.dy,
left: pos.dx,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onPanUpdate: _onPanUpdate,
// onTapDown: (_) {}, Doesn't affect the problem
child: Container(
width: 30.0,
height: 30.0,
color: Colors.red,
),
),
)
],
),
),
);
void _onPanUpdate(DragUpdateDetails details) {
RenderBox renderBox = context.findRenderObject();
setState(() {
pos = renderBox.globalToLocal(details.globalPosition);
});
}
}
但是,当开始拖动窗口小部件时,也会触发最外层容器的onTap,在这种情况下,背景暂时变为绿色。设置HitTestBehavior.opaque
似乎无法正常运行。也不向堆栈中的小部件添加onTapDown的处理程序。
那么,当用户与Stack内部的小部件进行交互时,如何防止onTapDown在最外面的GestureDetector上触发?
更新:
一个我遇到的问题的更简单的例子:
GestureDetector(
onTapDown: (_) {
print("Green");
},
child: Container(
color: Colors.green,
width: 300.0,
height: 300.0,
child: Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (_) {
print("Red");
},
child: Container(
color: Colors.red,
width: 50.0,
height: 50.0,
),
),
),
),
);
点击并按住红色容器时,即使内部的GestureDetector具有HitTestBehavior.opaque
,也会打印“红色”和“绿色”。
答案 0 :(得分:1)
在这个答案中,我将解决您给出的更简单的示例。您正在创建以下窗口小部件层次结构:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
因此,红色 GestureDetector是绿色 GestureDetector的子控件。 绿色 GestureDetector具有默认的HitTestBehavior:HitTestBehavior.deferToChild
。这就是两个容器都触发onTapDown
的原因。
服从其子女的目标会在其内部接受事件 仅当他们的一个孩子被命中测试命中时才划界。
相反,您可以使用Stack来构建UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
此结构将导致以下源代码。看起来一样,但是行为是您想要的:
Stack(
alignment: Alignment.center,
children: <Widget>[
GestureDetector(
onTapDown: (_) {
print("Green");
},
child: Container(
color: Colors.green,
width: 300.0,
height: 300.0,
),
),
GestureDetector(
onTapDown: (_) {
print("Red");
},
child: Container(
color: Colors.red,
width: 50.0,
height: 50.0,
),
)
],
)
答案 1 :(得分:0)
如Flutter开发者之一所述:https://github.com/flutter/flutter/issues/18450#issuecomment-397372078
opaque
仅表示手势检测器的整个大小都是命中区域,并不阻止孩子被命中。要阻止对孩子的点击,请使用IgnorePointer
或AbsorbPointer
。
您必须添加某种条件,以用IgnorePointer
包装孩子的Widget,这样顶部的GestureDetector将吸收水龙头。
在您的示例中,在这些小部件之间添加IgnorePointer
:
GestureDetector(
onTapDown: (_) {
print("Green");
},
child: IgnorePointer(
child: Container(
color: Colors.green,
width: 300.0,
height: 300.0,
child: Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (_) {
print("Red");
},
child: Container(
color: Colors.red,
width: 50.0,
height: 50.0,
),
),
),
),
),
);