skills/flutter/references/advanced-gestures.md

5.0 KiB

name description
advanced-gestures Flutter gestures - GestureDetector, GestureRecognizer, drag and drop, and gesture handling

Gestures

Flutter provides comprehensive gesture detection and handling capabilities.

GestureDetector

Detect various gestures on widgets.

GestureDetector(
  onTap: () {
    // Handle tap
  },
  onDoubleTap: () {
    // Handle double tap
  },
  onLongPress: () {
    // Handle long press
  },
  onPanUpdate: (details) {
    // Handle pan (drag)
    print('Delta: ${details.delta}');
  },
  onScaleUpdate: (details) {
    // Handle scale (pinch)
    print('Scale: ${details.scale}');
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
)

Tap Gestures

GestureDetector(
  onTap: () {
    print('Tapped');
  },
  onTapDown: (details) {
    print('Tap down at ${details.localPosition}');
  },
  onTapUp: (details) {
    print('Tap up at ${details.localPosition}');
  },
  onTapCancel: () {
    print('Tap cancelled');
  },
  child: Container(...),
)

Long Press

GestureDetector(
  onLongPress: () {
    print('Long pressed');
  },
  onLongPressStart: (details) {
    print('Long press started');
  },
  onLongPressEnd: (details) {
    print('Long press ended');
  },
  onLongPressMoveUpdate: (details) {
    print('Long press moved: ${details.localPosition}');
  },
  child: Container(...),
)

Pan Gestures (Drag)

class DraggableWidget extends StatefulWidget {
  const DraggableWidget({super.key});

  @override
  State<DraggableWidget> createState() => _DraggableWidgetState();
}

class _DraggableWidgetState extends State<DraggableWidget> {
  Offset _position = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: _position.dx,
      top: _position.dy,
      child: GestureDetector(
        onPanUpdate: (details) {
          setState(() {
            _position += details.delta;
          });
        },
        child: Container(
          width: 100,
          height: 100,
          color: Colors.blue,
        ),
      ),
    );
  }
}

Scale Gestures (Pinch)

class ScalableWidget extends StatefulWidget {
  const ScalableWidget({super.key});

  @override
  State<ScalableWidget> createState() => _ScalableWidgetState();
}

class _ScalableWidgetState extends State<ScalableWidget> {
  double _scale = 1.0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onScaleUpdate: (details) {
        setState(() {
          _scale = details.scale;
        });
      },
      child: Transform.scale(
        scale: _scale,
        child: Container(
          width: 100,
          height: 100,
          color: Colors.blue,
        ),
      ),
    );
  }
}

GestureRecognizer

Create custom gesture recognizers.

final _tapRecognizer = TapGestureRecognizer()
  ..onTap = () {
    print('Custom tap');
  };

RichText(
  text: TextSpan(
    text: 'Tap ',
    children: [
      TextSpan(
        text: 'here',
        style: TextStyle(color: Colors.blue),
        recognizer: _tapRecognizer,
      ),
    ],
  ),
)

@override
void dispose() {
  _tapRecognizer.dispose();
  super.dispose();
}

Drag and Drop

Use Draggable and DragTarget for drag and drop.

// Draggable widget
Draggable<String>(
  data: 'data',
  feedback: Container(
    width: 100,
    height: 100,
    color: Colors.blue.withOpacity(0.5),
  ),
  childWhenDragging: Container(
    width: 100,
    height: 100,
    color: Colors.grey,
  ),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
    child: const Center(child: Text('Drag me')),
  ),
)

// Drop target
DragTarget<String>(
  onAccept: (data) {
    print('Accepted: $data');
  },
  builder: (context, candidateData, rejectedData) {
    return Container(
      width: 200,
      height: 200,
      color: candidateData.isNotEmpty ? Colors.green : Colors.grey,
      child: const Center(child: Text('Drop here')),
    );
  },
)

Gesture Behavior

Control gesture behavior.

GestureDetector(
  behavior: HitTestBehavior.opaque, // opaque, translucent, deferToChild
  onTap: () {},
  child: Container(...),
)

Gesture Conflicts

Handle multiple gesture recognizers.

GestureDetector(
  onTap: () {
    print('Tap');
  },
  child: GestureDetector(
    onLongPress: () {
      print('Long press');
    },
    child: Container(...),
  ),
)

Key Points

  • Use GestureDetector for basic gesture detection
  • Handle tap, double tap, long press gestures
  • Use onPanUpdate for drag gestures
  • Use onScaleUpdate for pinch/zoom gestures
  • Use Draggable and DragTarget for drag and drop
  • Use GestureRecognizer for custom gesture handling
  • Set behavior to control hit testing
  • Dispose gesture recognizers to prevent leaks
  • GestureDetector can detect multiple gesture types simultaneously