손으로 혹은 버튼으로 카드 무한으로 좌 혹은 우로 날리기
import React, { useRef, useState } from 'react'
import { Animated, Easing, PanResponder } from 'react-native'
import styled from 'styled-components/native'
import { Ionicons } from '@expo/vector-icons'
import icons from './icons'
const Container = styled.View`
flex: 1;
justify-content: center;
align-items: center;
background-color: #00a8ff;
`
const Card = styled.View`
width: 300px;
height: 300px;
background-color: white;
justify-content: center;
align-items: center;
border-radius: 12px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
position: absolute;
`
const AnimatedCard = Animated.createAnimatedComponent(Card)
const Btn = styled.TouchableOpacity`
margin: 0px 10px;
`
const BtnContainer = styled.View`
flex-direction: row;
flex: 1;
`
const CardContainer = styled.View`
flex: 3;
justify-content: center;
align-items: center;
`
export default function App() {
const scale = useRef(new Animated.Value(1)).current
const position = useRef(new Animated.Value(0)).current
const rotation = position.interpolate({
inputRange: [-280, 280],
outputRange: ['-15deg', '15deg'],
extrapolate: 'clamp',
})
// position.addListener(() => console.log(rotation))
const secondScale = position.interpolate({
inputRange: [-300, 0, 300],
outputRange: [1, 0.5, 1],
extrapolate: 'clamp',
})
const onPressIn = Animated.spring(scale, {
toValue: 0.8,
useNativeDriver: true,
})
const onPressOut = Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
})
const goCenter = Animated.spring(position, {
toValue: 0,
useNativeDriver: true,
})
const goLeft = Animated.spring(position, {
toValue: -700,
useNativeDriver: true,
tension: 2,
restDisplacementThreshold: 100,
restSpeedThreshold: 100,
})
const goRight = Animated.spring(position, {
toValue: 700,
useNativeDriver: true,
tension: 5,
restDisplacementThreshold: 100,
restSpeedThreshold: 100,
})
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (_, { dx }) => {
position.setValue(dx)
},
onPanResponderGrant: () => onPressIn.start(),
onPanResponderRelease: (_, { dx }) => {
if (dx < -250) {
goLeft.start()
} else if (dx > 250) {
goRight.start()
} else {
Animated.parallel([onPressOut, goCenter]).start()
}
},
})
).current
const [index, setIndex] = useState(0)
const onDismiss = () => {
scale.setValue(1)
position.setValue(0)
setIndex((prev) => prev + 1)
}
const closePress = () => {
goLeft.start(onDismiss)
}
const checkPress = () => {
goRight.start(onDismiss)
}
return (
<Container>
<CardContainer>
<AnimatedCard style={{ transform: [{ scale: secondScale }] }}>
<Ionicons name={icons[index + 1]} color="#192a56" size={98} />
</AnimatedCard>
<AnimatedCard
{...panResponder.panHandlers}
style={{
transform: [
{ scale: scale },
{ translateX: position },
{ rotateZ: rotation },
],
}}
>
<Ionicons name={icons[index]} color="#192a56" size={98} />
</AnimatedCard>
</CardContainer>
<BtnContainer>
<Btn onPress={closePress}>
<Ionicons name="close-circle" color="white" size={58} />
</Btn>
<Btn onPress={checkPress}>
<Ionicons name="checkmark-circle" color="white" size={58} />
</Btn>
</BtnContainer>
</Container>
)
}