Skip to content

In GestureDetector, HorizontalDragGestureRecognizer takes precedence over ScaleGestureRecognizer #137189

@lastant

Description

@lastant

Is there an existing issue for this?

Steps to reproduce

  1. Create a demo app with the code below
  2. Try to do a scale (two finger pinch zoom) gesture in the center of the screen

Expected results

If both scale and drag events are defined, and I try to do a scale (pinch zoom) gesture, I expect the scale event to fire.

Actual results

Most of the time the drag event fires instead. Sometimes the scale event does fire.

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';

void main() {
  debugPrintGestureArenaDiagnostics = true;
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: GestureDetector(
        onTap: () {
          print("Tapped on full screen!");
        },
        onScaleStart: (details) {
          print('onScaleStart');
        },
        onScaleUpdate: (details) {
          print('onScaleUpdate');
        },
        onScaleEnd: (_) async {
          print('onScaleEnd');
        },
        onHorizontalDragStart: (_) {
          print('onHorizontalDragStart');
        },
        onHorizontalDragEnd: (_) async { 
          print('onHorizontalDragEnd');
        },
        onHorizontalDragUpdate: (DragUpdateDetails details) async {
          print('onHorizontalDragUpdate');
        },
        onTapDown: (TapDownDetails details) {
          print('onTapDown');
        },
        onTapCancel: () async {
          print('onTapCancel');
        },
        child: Container(
          // Set the size to occupy the full screen
          width: double.infinity,
          height: double.infinity,
          color: Colors.red, // Background color
        ),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs

The debug console shows:

I/flutter (13620): Gesture arena 1    ❙ ★ Opening new gesture arena.
I/flutter (13620): Gesture arena 1    ❙ Adding: TapGestureRecognizer#51f6a(debugOwner: GestureDetector, state: ready, button: 1)
I/flutter (13620): Gesture arena 1    ❙ Adding: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
I/flutter (13620): Gesture arena 1    ❙ Adding: ScaleGestureRecognizer#27a81(debugOwner: GestureDetector)
I/flutter (13620): Gesture arena 1    ❙ Closing with 3 members.
I/flutter (13620): Gesture arena 2    ❙ ★ Opening new gesture arena.
I/flutter (13620): Gesture arena 2    ❙ Adding: TapGestureRecognizer#51f6a(debugOwner: GestureDetector, state: possible, button: 1)
I/flutter (13620): Gesture arena 2    ❙ Adding: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
I/flutter (13620): Gesture arena 2    ❙ Adding: ScaleGestureRecognizer#27a81(debugOwner: GestureDetector)
I/flutter (13620): Gesture arena 2    ❙ Closing with 3 members.
I/flutter (13620): Gesture arena 1    ❙ Accepting: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
I/flutter (13620): Gesture arena 1    ❙ Self-declared winner: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
I/flutter (13620): onHorizontalDragStart
I/flutter (13620): Gesture arena 2    ❙ Accepting: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
I/flutter (13620): Gesture arena 2    ❙ Self-declared winner: HorizontalDragGestureRecognizer#7c597(debugOwner: GestureDetector, start behavior: start)
106
I/flutter (13620): onHorizontalDragUpdate
I/flutter (13620): onHorizontalDragEnd

meaning DoubleTapGestureRecognizer for some reason declares itself a winner, and the ScaleGestureRecognizer loses.

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.13.8, on Microsoft Windows [Version 10.0.22621.2428], locale en-US)
[✓] Windows Version (Installed version of Windows is version 10 or higher)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[✓] Android Studio (version 2022.3)
[✓] VS Code, 64-bit edition (version 1.83.1)
[✓] Connected device (1 available)
[✓] Network resources

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectf: gesturesflutter/packages/flutter/gestures repository.found in release: 3.13Found to occur in 3.13found in release: 3.16Found to occur in 3.16frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions