Nested GestureDetector OnTap Functions

2,618

Solution 1

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';

Solution 2

You can call todo1() in the nested onTap callback:

  GestureDetector(
        onTap: () {
            todo1(); 
        },
        child: GestureDetector(
            onTap: () {
                todo2();
                todo1();
            },
            child: Text("Nested Gesture")))
Share:
2,618
aLL
Author by

aLL

I just wanted to earn the Autobiographer badge so I wrote this

Updated on December 11, 2022

Comments

  • aLL
    aLL over 1 year

    I have nested GestureDetetors 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