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 'package:flutter/material.dart';
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 'package:flutter/material.dart';
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
GestureDetectorto detect specific gestures - Implement
onTapandonDoubleTapcarefully to avoid conflicts - Consider using
RawGestureDetectorfor 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.