Skip to main content

Working with Gestures

1. Using GestureDetector Widget

Example: Basic Tap Gesture

<GestureDetector
  onTap: () => print("Tapped!"),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
)>
Property Description Values
onTap Callback for tap gesture VoidCallback?
onDoubleTap Callback for double tap gesture VoidCallback?
onLongPress Callback for long press gesture VoidCallback?
onPanUpdate Callback for pan movement DragUpdateCallback?
Note: GestureDetector is a widget that detects gestures and calls the appropriate callback functions.

2. Detecting Tap Events

Property Values Description
onTap VoidCallback? Called when the user taps the widget.
onDoubleTap VoidCallback? Called when the user double-taps the widget.
onLongPress VoidCallback? Called when the user long-presses the widget.

Example: Basic Tap Detection

GestureDetector(
  onTap: () {
    print("Widget tapped!");
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
)

Example: Double Tap and Long Press

GestureDetector(
  onDoubleTap: () {
    print("Widget double-tapped!");
  },
  onLongPress: () {
    print("Widget long-pressed!");
  },
  child: Container(
    width: 150,
    height: 150,
    color: Colors.green,
  ),
)

3. Detecting Pan Gestures

Property Values Description
onPanUpdate void Function(DragUpdateDetails details) Callback when pan gesture updates
onPanEnd void Function(DragEndDetails details) Callback when pan gesture ends
onPanStart void Function(DragStartDetails details) Callback when pan gesture starts

Example: Pan Gesture Detection

GestureDetector(
  onPanUpdate: (DragUpdateDetails details) {
    print('Pan updated: ${details.delta}');
  },
  onPanEnd: (DragEndDetails details) {
    print('Pan ended');
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
)

4. Detecting Scale Gestures

Property Description Values
scale Current scale factor of the gesture double
focalPoint Point around which the scale is centered Offset

Example: Handling Scale Gesture

GestureDetector(
  onTap: () {
    print('Tapped');
  },
  onScaleStart: (ScaleStartDetails details) {
    print('Scale started at ${details.focalPoint}');
  },
  onScaleUpdate: (ScaleUpdateDetails details) {
    print('Scale factor: ${details.scale}');
  },
  onScaleEnd: (ScaleEndDetails details) {
    print('Scale ended');
  },
)

5. Using InkWell Widget

Example: Basic InkWell Usage

import &#x27;package:flutter/material.dart&#x27;;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("InkWell Example")),
        body: Center(
          child: InkWell(
            onTap: () {
              print("InkWell tapped!");
            },
            child: Container(
              padding: EdgeInsets.all(20),
              child: Text("Tap me!"),
            ),
          ),
        ),
      ),
    );
  }
}
Property Values Description
onTap VoidCallback? Called when the InkWell is tapped
onDoubleTap VoidCallback? Called when the InkWell is double-tapped
onLongPress VoidCallback? Called when the InkWell is long-pressed
highlightColor Color? Color used for the highlight effect
splashColor Color? Color used for the splash effect
borderRadius BorderRadius? Defines the rounded corners of the InkWell
Note: InkWell provides visual feedback for tap gestures but does not handle the actual gesture detection. It wraps its child and adds ink effects.

6. Using InkResponse Widget

Example: Basic InkResponse Usage

import &#x27;package:flutter/material.dart&#x27;;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("InkResponse Example")),
        body: Center(
          child: InkResponse(
            onTap: () {
              print("InkResponse tapped!");
            },
            child: Container(
              padding: EdgeInsets.all(20),
              child: Text("Tap me!"),
            ),
          ),
        ),
      ),
    );
  }
}
Property Values Description
onTap VoidCallback? Called when the ink response is tapped
onDoubleTap VoidCallback? Called when the ink response is double-tapped
onLongPress VoidCallback? Called when the ink response is long-pressed
child Widget The widget to display inside the ink response
highlightColor Color? The color to use for the highlight effect
splashColor Color? The color to use for the splash effect
enableFeedback bool Whether to enable haptic feedback
Note: InkResponse provides a more granular control over gesture handling compared to InkWell. It's useful when you need to customize the visual feedback or handle specific gestures.

7. Handling Gesture Conflicts

Example: GestureDetector with onTap and onDoubleTap

GestureDetector(
  onTap: () {
    print("Single tap");
  },
  onDoubleTap: () {
    print("Double tap");
  },
  child: Container(
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)
Property Description Notes
onTap Callback for single tap gesture Triggers on tap release
onDoubleTap Callback for double tap gesture May conflict with onTap
onLongPress Callback for long press gesture Can conflict with other gestures
Note: Use Dismissible or Draggable widgets to handle complex gesture interactions.
Warning: Conflicting gestures may cause unexpected behavior if not handled properly.

Best Practices for Gesture Conflicts

  • Use GestureDetector to detect specific gestures
  • Implement onTap and onDoubleTap carefully to avoid conflicts
  • Consider using RawGestureDetector for more control over gesture recognition

8. Using RawGestureDetector Widget

Example: Basic RawGestureDetector Usage

<RawGestureDetector
  gestures: {
    _CustomTapGestureRecognizer: GestureRecognizerFactoryWithHandlers<_CustomTapGestureRecognizer>(
      () => _CustomTapGestureRecognizer(),
      (instance) => instance..onTap = () {
        print('Custom tap recognized');
      },
    ),
  },
  child: Container(
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)
Property Description Values
gestures Map of gesture recognizers to handle Map<Type, GestureRecognizerFactoryWithHandlers>
child Widget to detect gestures on Widget
behavior How the gesture detector handles hit testing HitTestBehavior
Note: RawGestureDetector provides low-level access to gesture recognition and is useful when you need custom gesture handling not available in higher-level widgets.

9. Creating Custom Gesture Recognizers

Example: Basic Custom Gesture Recognizer

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

class CustomTapGestureRecognizer extends TapGestureRecognizer {
  CustomTapGestureRecognizer() {
    debugOwner = 'CustomTapGestureRecognizer';
  }

  @override
  void addHitTestable(HitTestable hitTestable) {
    super.addHitTestable(hitTestable);
  }

  @override
  void addPointer(PointerDownEvent event) {
    super.addPointer(event);
  }

  @override
  void handleEvent(PointerEvent event) {
    if (event is PointerUpEvent) {
      print('Custom tap recognized!');
    }
  }

  @override
  void cancel() {
    super.cancel();
  }

  @override
  String get debugDescription => 'CustomTapGestureRecognizer';
}

class CustomGestureWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print('Standard tap recognized');
      },
      child: Container(
        width: 200,
        height: 200,
        color: Colors.blue,
        child: Center(
          child: Text('Tap me'),
        ),
      ),
    );
  }
}
Property Description Usage
GestureRecognizer Base class for recognizing gestures Extend to create custom recognizers
addPointer Handles pointer events Override to customize event handling
handleEvent Processes pointer events Override to define gesture behavior
cancel Handles gesture cancellation Override to clean up state
Note: Custom gesture recognizers are useful for complex interactions that aren't covered by built-in recognizers.

10. Understanding Gesture Arena

Example: Gesture Recognition Flow

GestureDetector(
  onScaleStart: (ScaleStartDetails details) {
    print('Scale started');
  },
  onTap: () {
    print('Tap recognized');
  },
)
Gesture Description Recognition Phase
Scale Pinch-to-zoom gesture Start → Update → End
Tap Single tap recognition Recognized immediately
Long Press Hold gesture for duration Start → Update → End
Note: The gesture arena determines which gesture recognizer wins when multiple recognizers could handle the same event.

Gesture Arena Mechanics

  • Multiple recognizers can claim a gesture
  • Flutter uses an arena to resolve conflicts
  • Recognizers are evaluated in order of registration
  • Only one recognizer can win the arena

Was this article helpful?