dispatchDrag method

Future<void> dispatchDrag(
  1. double x,
  2. double y,
  3. double toX,
  4. double toY, {
  5. int holdMs = 600,
  6. int steps = 12,
})

Drags from (x, y) to (toX, toY).

holdMs is how long the pointer rests before moving — a long-press draggable needs it, a plain one does not. The move is sent in steps because a single jump does not look like a drag to a recogniser: it sees one enormous delta and no gesture in between.

Implementation

Future<void> dispatchDrag(
  double x,
  double y,
  double toX,
  double toY, {
  int holdMs = 600,
  int steps = 12,
}) async {
  final binding = GestureBinding.instance;
  final start = Offset(x, y);
  final end = Offset(toX, toY);
  var stamp = SchedulerBinding.instance.currentSystemFrameTimeStamp;
  final pointer = _nextPointer++;
  final kind = _pointerKind();

  final hitResult = HitTestResult();
  // ignore: deprecated_member_use
  binding.hitTest(hitResult, start);
  binding.dispatchEvent(
    PointerDownEvent(
        timeStamp: stamp, pointer: pointer, position: start, kind: kind),
    hitResult,
  );
  await Future<void>.delayed(Duration(milliseconds: holdMs));

  var previous = start;
  for (var i = 1; i <= steps; i++) {
    final position = Offset.lerp(start, end, i / steps)!;
    stamp += const Duration(milliseconds: 16);
    binding.dispatchEvent(
      PointerMoveEvent(
        timeStamp: stamp,
        pointer: pointer,
        position: position,
        delta: position - previous,
        kind: kind,
      ),
      hitResult,
    );
    previous = position;
    await Future<void>.delayed(const Duration(milliseconds: 16));
  }

  stamp += const Duration(milliseconds: 16);
  binding.dispatchEvent(
    PointerUpEvent(
        timeStamp: stamp, pointer: pointer, position: end, kind: kind),
    hitResult,
  );
}