skip to Main Content

I’m working on a project in react native using expo. I have a 2×2 style grid (4 cards in total are shown) where each card swipes left (no) or right (yes) of the screen. I need the next item of the flatlist to automatically appear in the space where the last swiped away item had been, but I’m struggling to figure out how to accomplish this. Here is an expo snack of what I currently have: Expo Snack. Does anyone know how to do this or if this is possible to do in a flatlist? I would really appreciate any help or advice. Thank you!

2

Answers


  1. I am thinking you can use useState hook for this. What you’ll see below is my initial attempt (just two new lines of code) and you can use it to build on your swiping logic thereafter.

    let newD = [];
    let dataFiltered = [
      {_id:1, color:"red"},
      {_id:2, color:"green"},
      {_id:3, color:"blue"},
      {_id:4, color:"pink"},
      {_id:5, color:"yellow"},
      {_id:6, color:"orange"},
      {_id:7, color:"purple"},
    ];
    const [data, setData] = useState(dataFiltered); // <- this is the first line to employ `useState` to your `dataFiltered`
    
    let errors;
    //console.log('filteredData', filteredData)
    console.log('dataFiltered', dataFiltered)
    const removeCard = (id) => {
    newD =  dataFiltered.splice(dataFiltered.findIndex((item) => item._id === id),1 );
    if (dataFiltered.length == 0) {
      setNoMoreCard(true);
    }
    setData(dataFiltered); // <- this is the second line to update the data array after swiping based on the `removeCard` function
    };
    

    Lastly, update the data props of your FlatList to {data} from {dataFiltered}.

    Login or Signup to reply.
  2. Here is the complete and tested example. Please check it.

    What I have done is just delete the card by id using the filter function and with the useState hook. cheers!

    import React, {useEffect, useState} from 'react';
    import {
      Animated,
      Dimensions,
      FlatList,
      PanResponder,
      SafeAreaView,
      StyleSheet,
      Text,
      View,
    } from 'react-native';
    
    const SCREEN_WIDTH = Dimensions.get('window').width;
    const SCREEN_HEIGHT = Dimensions.get('window').height;
    
    const SwipeableCard = ({item, removeCard, swipedDirection}) => {
      const [xPosition, setXPosition] = useState(new Animated.Value(0));
      let swipeDirection = '';
      let cardOpacity = new Animated.Value(1);
      let rotateCard = xPosition.interpolate({
        inputRange: [-200, 0, 200],
        outputRange: ['-20deg', '0deg', '20deg'],
      });
    
      let panResponder = PanResponder.create({
        onStartShouldSetPanResponder: (evt, gestureState) => false,
        onMoveShouldSetPanResponder: (evt, gestureState) => true,
        onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
        onPanResponderMove: (evt, gestureState) => {
          xPosition.setValue(gestureState.dx);
          if (gestureState.dx > SCREEN_WIDTH / 2 - 250) {
            swipeDirection = 'Right';
          } else if (gestureState.dx < -SCREEN_WIDTH / 2 + 250) {
            swipeDirection = 'Left';
          }
        },
        onPanResponderRelease: (evt, gestureState) => {
          if (
            gestureState.dx < SCREEN_WIDTH / 2 - 150 &&
            gestureState.dx > -SCREEN_WIDTH / 2 + 150
          ) {
            swipedDirection('');
            Animated.spring(xPosition, {
              toValue: 0,
              speed: 5,
              bounciness: 10,
              useNativeDriver: false,
            }).start();
          } else if (gestureState.dx > SCREEN_WIDTH / 2 - 150) {
            Animated.parallel([
              Animated.timing(xPosition, {
                toValue: SCREEN_WIDTH / 2,
                duration: 200,
                useNativeDriver: false,
              }),
              Animated.timing(cardOpacity, {
                toValue: 0,
                duration: 200,
                useNativeDriver: false,
              }),
            ]).start(() => {
              swipedDirection(swipeDirection);
              removeCard();
            });
          } else if (gestureState.dx < -SCREEN_WIDTH / 2 + 150) {
            Animated.parallel([
              Animated.timing(xPosition, {
                toValue: -SCREEN_WIDTH / 2,
                duration: 200,
                useNativeDriver: false,
              }),
              Animated.timing(cardOpacity, {
                toValue: 0,
                duration: 200,
                useNativeDriver: false,
              }),
            ]).start(() => {
              swipedDirection(swipeDirection);
              removeCard();
            });
          }
        },
      });
    
      return (
        <Animated.View
          {...panResponder.panHandlers}
          style={{
            opacity: cardOpacity,
            transform: [{translateX: xPosition}, {rotate: rotateCard}],
            //position: 'absolute',
            //top: -(SCREEN_HEIGHT)/2,
          }}>
          <View style={styles.card}>
            <View
              style={{
                flex: 1,
                height: 100,
                width: 200,
                backgroundColor: item.color,
                resizeMode: 'cover',
              }}
              //imageStyle={{ borderRadius: 10, paddingHorizontal:SCREEN_WIDTH*1/35,}}
              //source= {{ uri: item.profilePic}}
            >
              <Text style={{padding: 50}}>{item.color}</Text>
            </View>
          </View>
        </Animated.View>
      );
    };
    
    export default function HomeScreen() {
      const [swipeDirection, setSwipeDirection] = useState('');
    
      const [dataFiltered, setFilteredData] = useState([
        {_id: 1, color: 'red'},
        {_id: 2, color: 'green'},
        {_id: 3, color: 'blue'},
        {_id: 4, color: 'pink'},
        {_id: 5, color: 'yellow'},
        {_id: 6, color: 'orange'},
        {_id: 7, color: 'purple'},
        {_id: 8, color: '#0090FF'},
        {_id: 9, color: '#0001'},
        {_id: 10, color: 'gray'},
        {_id: 11, color: '#0089'},
      ]);
    
      const removeCard = id => {
        setFilteredData(dataFiltered.filter(item => item._id != id));
      };
    
      const lastSwipedDirection = swipeDirection => {
        setSwipeDirection(swipeDirection);
      };
    
      return (
        <SafeAreaView style={styles.container}>
          <FlatList
            style={styles.cardContainer}
            contentContainerStyle={{...styles.cardStack}}
            keyExtractor={(item, index) => index}
            numColumns={2}
            scrollEnabled={false}
            ListEmptyComponent={
              <View
                style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
                <Text>No More Cards</Text>
              </View>
            }
            data={dataFiltered}
            renderItem={({item, index}) => (
              <View style={{padding: 1}}>
                <SwipeableCard
                  key={index + item._id}
                  item={item}
                  removeCard={() => removeCard(item._id)}
                  swipedDirection={lastSwipedDirection}
                />
              </View>
            )}
          />
        </SafeAreaView>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        backgroundColor: 'white',
        //position: 'absolute',
        height: SCREEN_HEIGHT,
        flex: 0,
      },
      card: {
        height: SCREEN_HEIGHT / 2,
        width: SCREEN_WIDTH / 2,
        alignItems: 'center',
        justifyContent: 'center',
        alignContent: 'center',
        alignSelf: 'center',
        backgroundColor: 'white',
      },
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search