javascriptreact-nativereact-native-flatlist

How can I implement drag and drop functionality between two FlatLists in React Native?


I've searched online for solutions but haven't found a clear example or tutorial that fits my requirements. Can someone provide guidance on how to achieve this? Any libraries or approaches that can simplify the implementation would be greatly appreciated.

I need to implement drag and drop functionality between two FlatLists. Specifically, I have two FlatLists displaying different sets of items, and I want the user to be able to drag an item from one FlatList and drop it into the other.


Solution

  • You can use React Native DraxList and DraxView also GestureHandlerRootView Install with npm :

    npm i react-native-drax
    npm install react-native-gesture-handler
    

    Example:

    import { Image, StatusBar, StyleSheet, Text, TouchableOpacity, View, 
    Dimensions, FlatList, ScrollView } from "react-native";
    import React, { useState } from 'react';
    import { Colors } from "../colors";
    import { useNavigation } from "@react-navigation/native";
    import { GestureHandlerRootView } from 'react-native-gesture-handler';
    import { DraxProvider, DraxView, DraxList } from 'react-native-drax';
    
    
    const Home = () => {
    const draggableItemList = [
        {
            "id": 1,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 2,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 3,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 4,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 5,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
    
    ];
    const FirstReceivingItemList = [
        {
            "id": 5,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 6,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 7,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
        {
            "id": 8,
            "name": "EMI Calculators",
            "logo_url": "../images/2.png"
        },
    
    ];
    
    const [receivingItemList, setReceivedItemList] = React.useState(FirstReceivingItemList);
    const [dragItemMiddleList, setDragItemListMiddle] = React.useState(draggableItemList);
    
    const navigation = useNavigation();
    
    const DragUIComponent = ({ item, index }) => {
        return (
            <DraxView
                style={[styles.centeredContent, styles.draggableBox]}
                draggingStyle={styles.dragging}
                dragReleasedStyle={styles.dragging}
                hoverDraggingStyle={styles.hoverDragging}
                dragPayload={index}
                longPressDelay={150}
                key={index}
                receivingStyle={styles.receiving}
                renderContent={({ viewState }) => {
                
                    return (
                        <View style={{
                            alignItems: 'center',
                        }}>
                            <TouchableOpacity style={[styles.profileImgContainer, { backgroundColor: Colors.black }]} >
                                <Image source={require('../images/2.png')} style={styles.profileImg} />
                            </TouchableOpacity>
    
                            <Text style={styles.text1}>{item.name}
                            </Text>
                        </View>
                    );
                }}
            >
    
            </DraxView>
        );
    }
    
    const ReceivingZoneUIComponent = ({ item, index }) => {
        return (
            <DraxView
                style={[styles.centeredContent, styles.receivingZone]}
                dragPayload={index}
                receivingStyle={styles.receiving}
                renderContent={({ viewState }) => {
                    // const receivingDrag = viewState && viewState.receivingDrag;
                    // const payload = receivingDrag && receivingDrag.payload;
                    return (
                        <View style={{
                            alignItems: 'center',
                        }}>
                            <TouchableOpacity style={[styles.profileImgContainer, { backgroundColor: Colors.black }]} >
                                <Image source={require('../images/2.png')} style={styles.profileImg} />
                            </TouchableOpacity>
    
                            <Text style={styles.text1}>{item.name}
                            </Text>
                        </View>
                    );
                }}
                key={index}
            
            />
        );
    }
    
    const FlatListItemSeparator = () => {
        return (<View style={styles.itemSeparator} />);
    }
    
    return (
        <View style={styles.container}>
            <GestureHandlerRootView
                style={{ flex: 1 }}>
    
                <DraxProvider>
                    {/* <ScrollView> */}
                    
                        <View style={[styles.receivingContainer, {}]}>
                            <DraxView style={styles.innerLayout}
                             onReceiveDragDrop={(event) => {
                                console.log(event.dragged.payload)
                                let selected_item = dragItemMiddleList[event.dragged.payload];
                                let newReceivingItemList = [...receivingItemList];
                                newReceivingItemList[newReceivingItemList.length] = selected_item;
                                setReceivedItemList(newReceivingItemList);
            
                                const newDragItemMiddleList = [...dragItemMiddleList].filter((item) => item.id !== selected_item.id);
                                console.log(newDragItemMiddleList)
                                setDragItemListMiddle(newDragItemMiddleList);
                            }}>
                                <Text style={styles.headerText}>EMI Calculators</Text>
                                <DraxList
                                    data={receivingItemList}
                                    renderItemContent={ReceivingZoneUIComponent}
                                    keyExtractor={(item, index) => {index.toString()}}
                                    ItemSeparatorComponent={FlatListItemSeparator}
                                    numColumns={4}
                                    scrollEnabled={true}
                                />
                            </DraxView>
    
                        </View>
                        <DraxView style={styles.innerLayout}
                         onReceiveDragDrop={(event) => {
    
    
                            console.log(event.dragged.payload)
                            console.log(receivingItemList)
                            let selected_item = receivingItemList[event.dragged.payload];
                            console.log(selected_item)
                            let newReceivingItemList = [...dragItemMiddleList];
                            newReceivingItemList[newReceivingItemList.length] = selected_item;
                            setDragItemListMiddle(newReceivingItemList);
                            
        
                            const newDragItemMiddleList = [...receivingItemList].filter((item) => item.id !== selected_item.id);
                            console.log(newDragItemMiddleList)
                            setReceivedItemList(newDragItemMiddleList);
                            
                        }}
                        >
                            <Text style={styles.headerText}>Loan</Text>
                            <View style={styles.draxListContainer}>
                                <DraxList
                                    data={dragItemMiddleList}
                                    renderItemContent={DragUIComponent}
                                    keyExtractor={(item, index) => index.toString()}
                                    numColumns={4}
                                    ItemSeparatorComponent={FlatListItemSeparator}
                                    scrollEnabled={true}
                                />
                            </View>
                        </DraxView>
            
                </DraxProvider>
            </GestureHandlerRootView>
    
        </View>
    
    );
    
    };
    
    const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: Colors.backGroundColor,
    },
    
    innerLayout: {
        marginHorizontal: 10,
        paddingHorizontal:10,
        marginVertical: 5,
        borderRadius: 5,
        backgroundColor: Colors.innerBackGroundColor,
        borderColor: Colors.borderColor,
        borderWidth: 1,
    },
    innerLayout1: {
        marginStart: 10,
        marginVertical: 5,
        borderRadius: 5,
        backgroundColor: Colors.innerBackGroundColor,
        borderColor: Colors.borderColor,
        borderWidth: 1,
        flex: 1,
        padding: 10,
    },
    innerLayout2: {
        marginHorizontal: 10,
        marginVertical: 5,
        borderRadius: 5,
        borderColor: Colors.borderColor,
        borderWidth: 1,
        flex: 1,
        padding: 10,
    },
    
    headerText: {
        fontFamily: 'groww_sans_medium',
        fontSize: 20,
        color: Colors.white,
        marginVertical: 10,
    },
    
    text: {
        fontSize: 10,
        color: Colors.white,
        marginTop: 5,
        marginBottom: 10,
        textAlign: 'center',
        fontFamily: 'groww_sans_ragular'
    },
    text1: {
        fontSize: 10,
        color: Colors.white,
        marginTop: 5,
        textAlign: 'center',
        fontFamily: 'groww_sans_ragular'
    },
    profileImgContainer: {
        height: 35,
        width: 35,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 10,
        backgroundColor: Colors.white
    },
    
    profileImg: {
        height: 35,
        width: 35,
        borderRadius: 10,
    },
    
    leftContainer: {
        justifyContent: 'flex-start',
        flexDirection: 'row',
        alignItems: 'center',
        marginStart: 10
    },
    rightContainer: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'flex-end',
        alignItems: 'center',
        marginEnd: 10
    },
    
    receivingZone: {
        height: (Dimensions.get('window').width / 4) - 12,
        borderRadius: 10,
        width: (Dimensions.get('window').width / 4) - 12,
        justifyContent: 'center',
        alignItems: 'center',
        marginRight: 5
    },
    draggableBox: {
        width: (Dimensions.get('window').width / 4) - 12,
        height: (Dimensions.get('window').width / 4) - 12,
        borderRadius: 10,
        justifyContent: 'center',
        alignItems: 'center',
        marginRight: 5
    },
    
    });
    
    
    export default Home;