refactor(components): simplify SwipeableRow gesture handling and add vertical scroll conflict prevention
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useRef } from "react";
|
||||
import { View, Text, Pressable, Animated, StyleSheet } from "react-native";
|
||||
import { PanGestureHandler, State } from "react-native-gesture-handler";
|
||||
import { PanGestureHandler, State, PanGestureHandlerGestureEvent } from "react-native-gesture-handler";
|
||||
|
||||
type SwipeableRowProps = {
|
||||
children: React.ReactNode;
|
||||
@@ -8,37 +8,33 @@ type SwipeableRowProps = {
|
||||
deleteLabel?: string;
|
||||
};
|
||||
|
||||
const MAX_LEFT = -80;
|
||||
|
||||
export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: SwipeableRowProps) {
|
||||
const translateX = useRef(new Animated.Value(0)).current;
|
||||
const lastOffset = useRef(0);
|
||||
const offset = useRef(0);
|
||||
|
||||
const onGestureEvent = Animated.event([{ nativeEvent: { translationX: translateX } }], {
|
||||
useNativeDriver: true,
|
||||
});
|
||||
const onGestureEvent = (event: PanGestureHandlerGestureEvent) => {
|
||||
const raw = event.nativeEvent.translationX;
|
||||
const clamped = Math.max(MAX_LEFT, Math.min(0, offset.current + raw));
|
||||
translateX.setValue(clamped);
|
||||
};
|
||||
|
||||
const onHandlerStateChange = (event: any) => {
|
||||
const onHandlerStateChange = (event: PanGestureHandlerGestureEvent) => {
|
||||
if (event.oldState === State.ACTIVE) {
|
||||
const { translationX } = event.nativeEvent;
|
||||
const clampedTranslation = Math.min(0, translationX);
|
||||
const newOffset = lastOffset.current + clampedTranslation;
|
||||
const final = Math.max(MAX_LEFT, Math.min(0, offset.current + translationX));
|
||||
|
||||
if (newOffset < -80) {
|
||||
Animated.spring(translateX, {
|
||||
toValue: -80,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
lastOffset.current = -80;
|
||||
} else {
|
||||
Animated.spring(translateX, {
|
||||
toValue: 0,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
lastOffset.current = 0;
|
||||
}
|
||||
Animated.spring(translateX, {
|
||||
toValue: final,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
offset.current = final;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
offset.current = -400;
|
||||
Animated.timing(translateX, {
|
||||
toValue: -400,
|
||||
duration: 200,
|
||||
@@ -58,6 +54,7 @@ export function SwipeableRow({ children, onDelete, deleteLabel = "Delete" }: Swi
|
||||
<PanGestureHandler
|
||||
onGestureEvent={onGestureEvent}
|
||||
onHandlerStateChange={onHandlerStateChange}
|
||||
failOffsetY={[-5, 5]}
|
||||
>
|
||||
<Animated.View style={[styles.foreground, { transform: [{ translateX }] }]}>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user