Перейти к содержимому

18. Жесты (Gesture Handler)

react-native-gesture-handler — нативная обработка жестов. Работает в нативном потоке без JS bridge.

Окно терминала
npx expo install react-native-gesture-handler react-native-reanimated
// Обязательно в начале App.tsx!
import 'react-native-gesture-handler';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<Navigation />
</GestureHandlerRootView>
);
}
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
function DraggableBox() {
const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
const panGesture = Gesture.Pan()
.onUpdate((event) => {
offsetX.value = event.translationX;
offsetY.value = event.translationY;
})
.onEnd(() => {
offsetX.value = withSpring(0);
offsetY.value = withSpring(0);
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: offsetX.value },
{ translateY: offsetY.value },
],
}));
return (
<GestureDetector gesture={panGesture}>
<Animated.View style={[styles.box, animatedStyle]} />
</GestureDetector>
);
}
function ZoomableImage() {
const scale = useSharedValue(1);
const savedScale = useSharedValue(1);
const pinchGesture = Gesture.Pinch()
.onUpdate((e) => { scale.value = savedScale.value * e.scale; })
.onEnd(() => {
savedScale.value = scale.value;
if (scale.value < 1) { scale.value = withSpring(1); savedScale.value = 1; }
});
const style = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));
return (
<GestureDetector gesture={pinchGesture}>
<Animated.Image source={{ uri: imageUrl }} style={[styles.image, style]} />
</GestureDetector>
);
}
import Swipeable from 'react-native-gesture-handler/Swipeable';
function SwipeableItem({ item, onDelete }) {
const renderRightActions = () => (
<TouchableOpacity style={styles.deleteAction} onPress={onDelete}>
<Text style={{ color: '#fff' }}>Удалить</Text>
</TouchableOpacity>
);
return (
<Swipeable renderRightActions={renderRightActions}>
<View style={styles.item}><Text>{item.title}</Text></View>
</Swipeable>
);
}
// Одновременно pan + pinch (для карты)
const composed = Gesture.Simultaneous(panGesture, pinchGesture);
// Эксклюзивно (первый матч)
const exclusive = Gesture.Exclusive(longPressGesture, tapGesture);
// Последовательно
const sequence = Gesture.Race(longPressGesture, panGesture);