DEV Community

Nathan Rymarz
Nathan Rymarz

Posted on

Creating A Swipeable Card In React Native (part 2/3)

Gif of Swiping App

Continuing from the previous part, I will show you how we can display the next profile picture behind the current profile, add functionality to complete a swipe so that the next profile changes place with the current profile, and also add a reset animation so after an uncompleted swipe the current profile card's position will be elegantly reset.

To start with, let's add state to keep track of the next profile.

export default function App() {
  const [profile,setProfile] = useState(profiles[0])
  const [nextProfile, setNextProfile] = useState(profiles[1])
Enter fullscreen mode Exit fullscreen mode

Then, we can add a new View to our inside our return statement to render the new profile. So far, this is what our component returns:

return (
    <SafeAreaView style={styles.container}>
      <View style={styles.cardContainer}>
        <View style={styles.card}>
            <Image source={{uri: nextProfile.pic}} style={{height:"80%",width:"100%"}}></Image>
            <View style={{flex:1,alignContent:'center',justifyContent:'center'}}>
              <Text style={{fontSize:20,fontWeight:"700"}}>{nextProfile.name}</Text>
              <Text>Age: {nextProfile.age}</Text>
              <Text>Likes: {nextProfile.likes.join(', ')}</Text>
            </View>
        </View>
        <PanGestureHandler onGestureEvent={handlePan} onHandlerStateChange={handlePanStateChange}>
          <Animated.View style={[styles.card, {transform:[{translateX},{translateY},{rotate}]}]}>
            <Image source={{uri: profile.pic}} style={{height:"80%",width:"100%"}}></Image>
            <View style={{flex:1,alignContent:'center',justifyContent:'center'}}>
              <Text style={{fontSize:20,fontWeight:"700"}}>{profile.name}</Text>
              <Text>Age: {profile.age}</Text>
              <Text>Likes: {profile.likes.join(', ')}</Text>
            </View>
          </Animated.View>
        </PanGestureHandler>
      </View>
      <StatusBar style="auto" />
    </SafeAreaView>
  );
}
Enter fullscreen mode Exit fullscreen mode

Because we have the position style property set to 'absolute' for the cards the cards will overlap with the last one returned being rendered on top.

To make it so swiping will remove the current profile and set nextProfile to the front we will create a method to pass to the onHandlerStateChange prop for our PanGestureHandler. This method will take the nativeEvent as an argument and use it to determine if the current profile has been swiped far enough to qualify as a completed swipe, and if it has then execute the code for swiping.

  const handlePanStateChange = ({nativeEvent}) =>{
    const {state, translationX} = nativeEvent
    if(state === 5){ //When the user takes their finger off the screen
      if(translationX > 185 || translationX < -185){
        setProfile(nextProfile)
        setNextProfile(profiles[++index%3])
      }
    }
  }
Enter fullscreen mode Exit fullscreen mode

The last thing to do is get the current profile card to reset position automatically after an uncompleted swipe. To do this, we will make an Animation with Animated.parallel to reset both the x and y position back to zero. Here is what I used:

const reset = Animated.parallel([
    Animated.timing(translateX,{
      toValue:0,
      duration:200,
      useNativeDriver:true
    }),
    Animated.timing(translateY,{
      toValue:0,
      duration:200,
      useNativeDriver:true
    })
  ])
Enter fullscreen mode Exit fullscreen mode

And now we just need to call reset inside our handlePanStateChange method when the user doesn't swipe far enough.

const handlePanStateChange = ({nativeEvent}) =>{
    const {state, translationX} = nativeEvent
    if(state === 5){ //When the user takes their finger off the screen
      if(translationX > 185 || translationX < -185){
        setProfile(nextProfile)
        setNextProfile(profiles[++index%3])
      }
      else reset.start()
    }
  }
Enter fullscreen mode Exit fullscreen mode

And that's it! Our cards are now swipeable and appear as though we are swiping off the top of a deck of cards. In the next tutorial, I will show you how we can animate the top card off the screen while still allowing the card behind it to be interactable.

Discussion (0)