Reputation: 1726
I have nested GestureDetetor
s but problem is that only the child GestureDetector
's onTap
is executed. I do not wish to override the child's onTap, rather, I want both the parent's and the child's onTap to execute. Here's my code:
GestureDetector(
onTap: () {
todo1();
},
child: GestureDetector(
onTap: () {
todo2();
},
child: Text("Nested Gesture")))
How do I change this to call both todo1()
and todo2()
onTap?
edit: the child is a re-usable custom widget that has its own implementation but is now being used by the parent which also has an implementation of its own in addition to its child
Upvotes: 13
Views: 5955
Reputation: 1083
The issue is mentioned in the official docs 🤓 - https://api.flutter.dev/flutter/widgets/GestureDetector-class.html#widgets.GestureDetector.3
If you have two competing gesture detectors the nested one wins even though set to translucent, implement the onTapDown on the parent detector to still receive the tap event.
GestureDetector(
onTapDown: (_) => todo1(), // this should do the trick
child: GestureDetector(
onTap: () {
todo2();
},
child: Text("Nested Gesture")))
Upvotes: 0
Reputation: 1167
If you want both the parent’s and child’s onTap methods to execute, you can use the following code snippet:
GestureDetector(
onTap: () {
// parent onTap method
},
child: GestureDetector(
onTap: () {
// child onTap method
},
behavior: HitTestBehavior.translucent,
child: Container(),
),
);
The behavior property is set to HitTestBehavior.translucent
, which allows both the parent and child widgets to receive taps.
Upvotes: -1
Reputation: 201
You can call todo1() in the nested onTap callback:
GestureDetector(
onTap: () {
todo1();
},
child: GestureDetector(
onTap: () {
todo2();
todo1();
},
child: Text("Nested Gesture")))
Upvotes: -2
Reputation: 10354
I made a quick custom gesture recognizer - it cancels the gesture only if user has moved too far from the initial tap point.
Usage example:
UniversalTapHandler(
onTap: () {
print("Tap 1");
},
child: UniversalTapHandler(
onTap: () {
print("Tap 2");
},
child: Text("Nested Gesture"),
)
)
Source code:
class UniversalTapHandler extends RawGestureDetector {
UniversalTapHandler({
@required GestureTapCallback onTap,
@required Widget child,
}):
super(
gestures: <Type, GestureRecognizerFactory>{
_UniversalPointerHandler: GestureRecognizerFactoryWithHandlers<_UniversalPointerHandler>(
() => _UniversalPointerHandler(onTap: onTap),
(_) {},
),
},
child: child,
);
}
class _UniversalPointerHandler extends OneSequenceGestureRecognizer {
_UniversalPointerHandler({
@required this.onTap,
}): super();
final GestureTapCallback onTap;
final _maxDistance = 18; // as in official recognizer by default
Offset _startPosition;
void _reset() {
_startPosition = null;
}
@override
void addPointer(PointerDownEvent event) {
_startPosition = event.position;
startTrackingPointer(event.pointer);
resolve(GestureDisposition.accepted);
}
@override
void handleEvent(PointerEvent event) {
if (event is PointerUpEvent) {
stopTrackingPointer(event.pointer);
if (_startPosition != null) {
onTap();
}
}
if (event is PointerMoveEvent && _startPosition != null) {
if ((event.position - _startPosition).distance > _maxDistance) {
rejectGesture(event.pointer);
_reset();
}
}
if (event is PointerCancelEvent || event is PointerExitEvent || event is PointerRemovedEvent) {
_reset();
}
}
@override
void resolve(GestureDisposition disposition) {
if (disposition == GestureDisposition.rejected) {
_reset();
}
super.resolve(disposition);
}
@override
void didStopTrackingLastPointer(int pointer) {}
@override
String get debugDescription => "_UniversalPointerHandler: Custom Gesture Recognizer";
}
UPDATE Don't forget to import this:
import 'package:flutter/gestures.dart';
Upvotes: 4