I'm using a swipe animation, the same one that is being used in apps like tinder. The animation used to work in a Class component and in JSX but I had to change it to a function with hooks in TSX for a project. Now the animation Doensn't work anymore but it also doesn't give a error. I guess I'm missing some code that is necessary to let it work or it also can be something with the Panresponder. But I absolutely got no clue.
Thanks in advance.
const SCREEN_HEIGHT = Dimensions.get('window').height
const SCREEN_WIDTH = Dimensions.get('window').width
const { width, height } = Dimensions.get('screen')
const thumbMeasure = (width - 48 - 32) / 3
const MyComponent = (props: { index: any }) => {
const [imagesData, setImagesData] = useState<Images[]>([])
console.clear()
console.log('Images data:', imagesData)
useEffect(() => {
LogBox.ignoreLogs(['Animated: `useNativeDriver`']);
}, [])
useEffect(() => {
axios
.get<Images[]>('https://api.thecatapi.com/v1/images/search?breed_ids=beng&include_breeds=true')
.then((response: AxiosResponse) => {
setImagesData(response.data)
})
}, [])
const position = new Animated.ValueXY()
const [index, setIndex] = useState(props.index || 0)
const [panResponder, setPanResponder] = useState<any>()
const rotate = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: ['-30deg', '0deg', '10deg'],
extrapolate: 'clamp',
})
const rotateAndTranslate = {
transform: [{
rotate: rotate
},
...position.getTranslateTransform()
]
}
const likeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
})
const dislikeOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 0],
extrapolate: 'clamp',
})
const nextCardOpacity = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0, 1],
extrapolate: 'clamp',
})
const nextCardScale = position.x.interpolate({
inputRange: [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2],
outputRange: [1, 0.8, 1],
extrapolate: 'clamp',
})
useEffect(() => {
setPanResponder( PanResponder.create({
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
onPanResponderMove: (_evt, gestureState) => {
position.setValue({ x: gestureState.dx, y: gestureState.dy })
},
onPanResponderRelease: (_evt, gestureState) => {
if (gestureState.dx > 120) {
Animated.spring(position, {
toValue: { x: SCREEN_WIDTH + 100, y: gestureState.dy },
useNativeDriver: true,
}).start(() => {
setIndex( () => {
position.setValue({ x: 0, y: 0 })
return index + 1
})
})
} else if (gestureState.dx < -120) {
Animated.spring(position, {
toValue: { x: -SCREEN_WIDTH - 100, y: gestureState.dy },
useNativeDriver: true,
}).start(() => {
setIndex( () => {
position.setValue({ x: 0, y: 0 })
return index + 1
})
})
} else {
Animated.spring(position, {
toValue: { x: 0, y: 0 },
friction: 4, useNativeDriver: true,
}).start()
}
},
}))
}, [])
const Users = () => {
return imagesData.map((item, i) => {
if (i < index) {
return null
} else if (i == index) {
return (
<Animated.View
{...panResponder.panhandlers}
key={item.id}
style={[
rotateAndTranslate,
{
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: likeOpacity,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: dislikeOpacity,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
<View style={{backgroundColor: '', color: 'black', fontSize: 20, fontWeight: '800', position: 'absolute', bottom: 95, right: 40, zIndex: 1000, width: '85%', height: '20%', borderRadiusTop: 20, }}>
<Text style={{ color: 'white', fontSize: 32, fontWeight: '800' }}>
{item.breeds[0].name}
</Text>
<Text style={{ color: 'white', fontSize: 18, fontWeight: '600' }}>
{item.breeds[0].origin}
</Text>
<View style={styles.iconen}>
<Ionicons style={styles.icon} name="timer" />
<Text style={styles.subtitle}>{item.breeds[0].life_span}</Text>
<Ionicons style={styles.icon} name="barbell-outline" />
<Text style={styles.subtitle}>{item.breeds[0].weight.metric}</Text>
<Ionicons style={styles.icon} name="earth" />
<Text style={styles.subtitle}>{item.breeds[0].country_code}</Text>
</View>
</View>
</Animated.View>
)
} else {
return (
<Animated.View
key={item.id}
style={[
{
opacity: nextCardOpacity,
transform: [{ scale: nextCardScale }],
height: SCREEN_HEIGHT - 120,
width: SCREEN_WIDTH,
padding: 10,
position: 'absolute',
},
]}
>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '-30deg' }],
position: 'absolute',
top: 50,
left: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'green',
color: 'green',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
LIKE
</Text>
</Animated.View>
<Animated.View
style={{
opacity: 0,
transform: [{ rotate: '30deg' }],
position: 'absolute',
top: 50,
right: 40,
zIndex: 1000,
}}
>
<Text
style={{
borderWidth: 1,
borderColor: 'red',
color: 'red',
fontSize: 32,
fontWeight: '800',
padding: 10,
}}
>
NOPE
</Text>
</Animated.View>
<Image
style={{ height: '86%', width: null, borderRadius: 10 }}
source={{ uri: `${item.url}` }}
/>
</Animated.View>
)
}
})
.reverse()
}
return (
<View>
<View>
{Users()}
</View>
<View style={{ height: SCREEN_HEIGHT - 80 }}>
<ButtonVote />
</View>
</View>
)
}