My React Native 0.64 app uses react-native-gesture-handler 1.16/react-native-reanimated 2.1 to swipe images left and right. The idea is when user clicks a image in image gallery, then the image was displayed occupying the full screen and the rest of images in the gallery can be viewed one by one by swipe left or right. Here is the full code which swipe works but with one catch: the image clicked is not presented but the first image in gallery is always shown first. How to land on the image a user has clicked?
import React, { useRef } from "react";
import { Dimensions, StyleSheet, View, Platform } from "react-native";
import FastImage from 'react-native-fast-image';
import Animated, {
useAnimatedStyle,
useSharedValue,
useAnimatedRef,
useAnimatedGestureHandler,
useAnimatedReaction,
withTiming,
withSpring,
useDerivedValue,
} from "react-native-reanimated";
import {
snapPoint,
} from "react-native-redash";
import {
PanGestureHandler,
PinchGestureHandler,
State,
TouchableOpacity,
} from "react-native-gesture-handler";
const { width, height } = Dimensions.get("window");
export default Swipe = ({route, navigation}) => {
const {images, initIndex} = route.params; //initIndex is the index of image clicked
console.log("route params swipe ", route.params);
const index = useSharedValue(initIndex);
const snapPoints = images.map((_, i) => i * -width);
const panRef = useAnimatedRef();
const pinchRef = useAnimatedRef();
const offsetX = initIndex ? useSharedValue(initIndex * -width) : useSharedValue(0); //The init offsetX is set according to initIndex a user clicked.
const translationX = useSharedValue(0);
const translateX = useSharedValue(0); //if translateX was assgined with offsetX, then swipe stops working
//for snap in swipe
const lowVal = useDerivedValue(() => {return (index.value + 1) * -width}); //shared value, with .value
const highVal = useDerivedValue(() => {return (index.value - 1) * -width}); //shared value, with .value
const snapPt = (e) => {
"worklet";
return snapPoint(translateX.value, e.velocityX, snapPoints);
};
const panHandler = useAnimatedGestureHandler(
{
onStart: () => {
translateX.value = offsetX.value; //As soon as a user swipe, this line allow the
//image is moved to initIndex-th image. But how to land on the image a user has clicked?
},
onActive: (event) => {
translateX.value = offsetX.value + event.translationX;
translationX.value = event.translationX;
},
onEnd: (event) => {
let val = snapPt(event);
let sp = Math.min(Math.max(lowVal.value, val), highVal.value); //clamp in RN redash
if (event.translationX !== 0) {
translateX.value = withTiming(sp);
offsetX.value = translateX.value;
};
//update index
index.value = Math.floor(translateX.value/-width);
},
}, []
)
const swipeStyle = useAnimatedStyle(() => {
return {
transform: [{ translateX: translateX.value}]
}
});
return (
<PanGestureHandler
onGestureEvent={panHandler}
ref={panRef}
minDist={10}
avgTouches
>
<Animated.View style={styles.container}>
<Animated.View
style={[{width: width * images.length, height, flexDirection: "row"}, swipeStyle]}
>
{images.map((img_source, i) => {
const isActive = useDerivedValue(() => {return index.value === i});
return (
<View key={i} style={styles.picture}>
<View style={[
styles.image,
]}>
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.button}>
<View style={styles.button}>
<FastImage
source={{uri:img_source.path}}
resizeMode={FastImage.resizeMode.contain}
style={styles.image}
/>
</View>
</TouchableOpacity>
</View>
</View>
);
})}
</Animated.View>
</Animated.View>
</PanGestureHandler>
);
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
backgroundColor: "black",
},
picture: {
width,
height,
overflow: "hidden",
},
image: {
//...StyleSheet.absoluteFillObject,
flex:1,
width: undefined,
height: undefined,
//resizeMode: "cover",
},
button: {
width: width,
height:height,
},
});
Another issue the code is that when touching the image before swipe the image jerks left or right 1/3-1/2 screen width. This makes the swipe un-smooth. I would like to know how to eliminate the image jerk and make the swipe smooth from beginning to the end.