Gesture Detection in Flitter
Gesture detection in Flitter enables you to create interactive user interfaces by responding to various user inputs such as taps, drags, and mouse events. The GestureDetector widget provides a comprehensive API for handling these interactions.
Core Concepts
- Event Types: Various gesture events including clicks, drags, and mouse movements
- Event Data: Detailed information about the gesture (coordinates, pressure, etc.)
- Propagation: How events flow through the widget tree
- State Management: Handling gesture state and updates
Basic Usage
Simple click detection:
import { GestureDetector, Container } from "@meursyphus/flitter";
const clickableContainer = GestureDetector({
onClick: (e) => {
console.log("Clicked at:", e.clientX, e.clientY);
},
child: Container({
width: 200,
height: 200,
color: "blue",
}),
});
Gesture Types
Click/Tap Events
GestureDetector({
onClick: (e) => {
console.log("Single click");
},
onDoubleClick: (e) => {
console.log("Double click");
},
child: /* your widget */,
});
Drag Events
GestureDetector({
onDragStart: (e) => {
console.log("Started dragging");
},
onDragUpdate: (e) => {
console.log("Dragging at:", e.clientX, e.clientY);
console.log("Delta:", e.delta.x, e.delta.y);
},
onDragEnd: (e) => {
console.log("Finished dragging");
},
child: /* your widget */,
});
Mouse Events
GestureDetector({
onMouseEnter: (e) => {
console.log("Mouse entered");
},
onMouseMove: (e) => {
console.log("Mouse position:", e.clientX, e.clientY);
},
onMouseLeave: (e) => {
console.log("Mouse left");
},
child: /* your widget */,
});
Advanced Usage
Combining Multiple Gestures
import { GestureDetector, Container, useState } from "@meursyphus/flitter";
function InteractiveBox() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const [isHovered, setIsHovered] = useState(false);
return GestureDetector({
onDragUpdate: (e) => {
setPosition({
x: position.x + e.delta.x,
y: position.y + e.delta.y,
});
},
onMouseEnter: () => setIsHovered(true),
onMouseLeave: () => setIsHovered(false),
child: Container({
width: 100,
height: 100,
offset: position,
color: isHovered ? "red" : "blue",
}),
});
}
Custom Gesture Recognition
Creating a custom long-press detector:
function LongPressDetector({ onLongPress, child }) {
let pressTimer;
return GestureDetector({
onPointerDown: () => {
pressTimer = setTimeout(onLongPress, 500);
},
onPointerUp: () => {
clearTimeout(pressTimer);
},
onPointerCancel: () => {
clearTimeout(pressTimer);
},
child,
});
}
Best Practices
-
Event Handling:
- Keep event handlers small and focused
- Avoid expensive operations in handlers
- Consider debouncing for frequent events
-
User Experience:
- Provide visual feedback for interactions
- Maintain consistent behavior
- Consider touch and mouse interactions
-
Performance:
- Use appropriate event types
- Optimize drag handlers
- Clean up event listeners
-
Accessibility:
- Support keyboard navigation
- Provide alternative interactions
- Consider users with different abilities
Common Patterns
Draggable Widget
function DraggableWidget({ child }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
return GestureDetector({
onDragUpdate: (e) => {
setPosition({
x: position.x + e.delta.x,
y: position.y + e.delta.y,
});
},
child: Container({
offset: position,
child,
}),
});
}
Interactive Button
function InteractiveButton({ onPress, child }) {
const [isPressed, setIsPressed] = useState(false);
return GestureDetector({
onPointerDown: () => setIsPressed(true),
onPointerUp: () => {
setIsPressed(false);
onPress();
},
onPointerCancel: () => setIsPressed(false),
child: Container({
scale: isPressed ? 0.95 : 1,
child,
}),
});
}
Troubleshooting
Event Propagation
Handle event propagation correctly:
GestureDetector({
onClick: (e) => {
e.stopPropagation(); // Prevent event from bubbling up
// Handle click
},
child: /* your widget */,
});
Gesture Conflicts
Resolve conflicts between different gesture handlers:
Stack({
children: [
// Background handler
GestureDetector({
onClick: (e) => {
// Only handle if not handled by child
if (!e.defaultPrevented) {
handleBackgroundClick();
}
},
child: Container({
/* ... */
}),
}),
// Foreground handler
GestureDetector({
onClick: (e) => {
e.preventDefault(); // Prevent background handling
handleForegroundClick();
},
child: Container({
/* ... */
}),
}),
],
});
Conclusion
Gesture detection is fundamental to creating interactive Flitter applications. The GestureDetector widget provides a rich API for handling user interactions, enabling you to create responsive and engaging user interfaces. Remember to consider both desktop and mobile interactions, maintain consistent behavior, and optimize performance for smooth user experiences.