How do I prevent onTapDown from being triggered on a parent widgets GestureDetector?
up vote
1
down vote
favorite
I have a Stack in which several widget can be dragged around. In addition, the container that the Stack is in has a GestureDetector to trigger on onTapDown and onTapUp. I want those onTap events only to be triggered when the user taps outside of the widget in the Stack. I've tried the following code:
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);
});
}
}
However, when starting to drag the widget, the onTap of the outermost container is triggered as well, making the background momentarily go green in this case. Settings HitTestBehavior.opaque
doesn't seem to work like I'd expect. Neither does adding a handler for onTapDown to the widget in the Stack.
So, how do I prevent onTapDown from being triggered on the outermost GestureDetector when the user interacts with the widget inside of the Stack?
Update:
An even simpler example of the problem I'm encountering:
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,
),
),
),
),
);
When I tap and hold the red container, both "Red" and "Green" are printed even though the inner GestureDetector has HitTestBehavior.opaque
.
flutter gesture-recognition
add a comment |
up vote
1
down vote
favorite
I have a Stack in which several widget can be dragged around. In addition, the container that the Stack is in has a GestureDetector to trigger on onTapDown and onTapUp. I want those onTap events only to be triggered when the user taps outside of the widget in the Stack. I've tried the following code:
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);
});
}
}
However, when starting to drag the widget, the onTap of the outermost container is triggered as well, making the background momentarily go green in this case. Settings HitTestBehavior.opaque
doesn't seem to work like I'd expect. Neither does adding a handler for onTapDown to the widget in the Stack.
So, how do I prevent onTapDown from being triggered on the outermost GestureDetector when the user interacts with the widget inside of the Stack?
Update:
An even simpler example of the problem I'm encountering:
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,
),
),
),
),
);
When I tap and hold the red container, both "Red" and "Green" are printed even though the inner GestureDetector has HitTestBehavior.opaque
.
flutter gesture-recognition
I don't know if it can help, but cuold you try chanhe outerGestureDetector
toListener
?
– Andrey Turkovsky
Nov 9 at 20:01
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have a Stack in which several widget can be dragged around. In addition, the container that the Stack is in has a GestureDetector to trigger on onTapDown and onTapUp. I want those onTap events only to be triggered when the user taps outside of the widget in the Stack. I've tried the following code:
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);
});
}
}
However, when starting to drag the widget, the onTap of the outermost container is triggered as well, making the background momentarily go green in this case. Settings HitTestBehavior.opaque
doesn't seem to work like I'd expect. Neither does adding a handler for onTapDown to the widget in the Stack.
So, how do I prevent onTapDown from being triggered on the outermost GestureDetector when the user interacts with the widget inside of the Stack?
Update:
An even simpler example of the problem I'm encountering:
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,
),
),
),
),
);
When I tap and hold the red container, both "Red" and "Green" are printed even though the inner GestureDetector has HitTestBehavior.opaque
.
flutter gesture-recognition
I have a Stack in which several widget can be dragged around. In addition, the container that the Stack is in has a GestureDetector to trigger on onTapDown and onTapUp. I want those onTap events only to be triggered when the user taps outside of the widget in the Stack. I've tried the following code:
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);
});
}
}
However, when starting to drag the widget, the onTap of the outermost container is triggered as well, making the background momentarily go green in this case. Settings HitTestBehavior.opaque
doesn't seem to work like I'd expect. Neither does adding a handler for onTapDown to the widget in the Stack.
So, how do I prevent onTapDown from being triggered on the outermost GestureDetector when the user interacts with the widget inside of the Stack?
Update:
An even simpler example of the problem I'm encountering:
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,
),
),
),
),
);
When I tap and hold the red container, both "Red" and "Green" are printed even though the inner GestureDetector has HitTestBehavior.opaque
.
flutter gesture-recognition
flutter gesture-recognition
edited Nov 10 at 10:39
asked Nov 9 at 18:57
spkersten
1408
1408
I don't know if it can help, but cuold you try chanhe outerGestureDetector
toListener
?
– Andrey Turkovsky
Nov 9 at 20:01
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21
add a comment |
I don't know if it can help, but cuold you try chanhe outerGestureDetector
toListener
?
– Andrey Turkovsky
Nov 9 at 20:01
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21
I don't know if it can help, but cuold you try chanhe outer
GestureDetector
to Listener
?– Andrey Turkovsky
Nov 9 at 20:01
I don't know if it can help, but cuold you try chanhe outer
GestureDetector
to Listener
?– Andrey Turkovsky
Nov 9 at 20:01
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
In this answer, I'll solve the simpler example you have given. You are creating the following Widget hierarchy:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
Therefore the red GestureDetector is a child Widget of the green GestureDetector. The green GestureDetector has the default HitTestBehavior: HitTestBehavior.deferToChild
. That is why onTapDown
is fired for both containers.
Targets that defer to their children receive events within their
bounds only if one of their children is hit by the hit test.
Instead, you can use a Stack to build your UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
This structure would result in the follwing sourcecode. It looks the same, but the behavior is the one you desired:
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,
),
)
],
)
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
In this answer, I'll solve the simpler example you have given. You are creating the following Widget hierarchy:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
Therefore the red GestureDetector is a child Widget of the green GestureDetector. The green GestureDetector has the default HitTestBehavior: HitTestBehavior.deferToChild
. That is why onTapDown
is fired for both containers.
Targets that defer to their children receive events within their
bounds only if one of their children is hit by the hit test.
Instead, you can use a Stack to build your UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
This structure would result in the follwing sourcecode. It looks the same, but the behavior is the one you desired:
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,
),
)
],
)
add a comment |
up vote
0
down vote
In this answer, I'll solve the simpler example you have given. You are creating the following Widget hierarchy:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
Therefore the red GestureDetector is a child Widget of the green GestureDetector. The green GestureDetector has the default HitTestBehavior: HitTestBehavior.deferToChild
. That is why onTapDown
is fired for both containers.
Targets that defer to their children receive events within their
bounds only if one of their children is hit by the hit test.
Instead, you can use a Stack to build your UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
This structure would result in the follwing sourcecode. It looks the same, but the behavior is the one you desired:
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,
),
)
],
)
add a comment |
up vote
0
down vote
up vote
0
down vote
In this answer, I'll solve the simpler example you have given. You are creating the following Widget hierarchy:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
Therefore the red GestureDetector is a child Widget of the green GestureDetector. The green GestureDetector has the default HitTestBehavior: HitTestBehavior.deferToChild
. That is why onTapDown
is fired for both containers.
Targets that defer to their children receive events within their
bounds only if one of their children is hit by the hit test.
Instead, you can use a Stack to build your UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
This structure would result in the follwing sourcecode. It looks the same, but the behavior is the one you desired:
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,
),
)
],
)
In this answer, I'll solve the simpler example you have given. You are creating the following Widget hierarchy:
- GestureDetector // green
- Container
- Center
- GestureDetector // red
- Container
Therefore the red GestureDetector is a child Widget of the green GestureDetector. The green GestureDetector has the default HitTestBehavior: HitTestBehavior.deferToChild
. That is why onTapDown
is fired for both containers.
Targets that defer to their children receive events within their
bounds only if one of their children is hit by the hit test.
Instead, you can use a Stack to build your UI:
- Stack
- GestureDetector // green
- Container
- GestureDetector // red
- Container
This structure would result in the follwing sourcecode. It looks the same, but the behavior is the one you desired:
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,
),
)
],
)
answered Nov 12 at 9:22
Niklas
3447
3447
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53231796%2fhow-do-i-prevent-ontapdown-from-being-triggered-on-a-parent-widgets-gesturedetec%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I don't know if it can help, but cuold you try chanhe outer
GestureDetector
toListener
?– Andrey Turkovsky
Nov 9 at 20:01
@AndreyTurkovsky I'm not sure if I understand what you mean. Just replacing the outer detector with a Listener and using onPointerDown etc. like I used onTapDown does fix the problem. (This is a reduced example, in the real code the outer GestureDetector is further up the stack in a different Widget. So I'd prefer no to change that GestureDetector if possible)
– spkersten
Nov 9 at 20:21