skip to Main Content

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.

2

Answers


  1. You can use React Native Draggable FlatList
    Install with npm :

    npm install --save react-native-draggable-flatlist
    

    or with yarn:

    yarn add react-native-draggable-flatlist
    

    and use by importing:

    import DraggableFlatList from 'react-native-draggable-flatlist'
    

    Example:

    
    import React, { useState } from "react";
    import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
    import DraggableFlatList, {
      ScaleDecorator,
      onDragEnd,
    } from "react-native-draggable-flatlist";
    
    const NUM_ITEMS = 10;
    function getColor(i: number) {
      const multiplier = 255 / (NUM_ITEMS - 1);
      const colorVal = i * multiplier;
      return `rgb(${colorVal}, ${Math.abs(128 - colorVal)}, ${255 - colorVal})`;
    }
    
    type Item = {
      key: string;
      label: string;
      height: number;
      width: number;
      backgroundColor: string;
      listId: string; // new property to identify list
    };
    
    const initialDataLeft: Item[] = [...Array(NUM_ITEMS / 2)].map((d, index) => {
      const backgroundColor = getColor(index);
      return {
        key: `left-item-${index}`,
        label: String(index) + "",
        height: 100,
        width: 60 + Math.random() * 40,
        backgroundColor,
        listId: "left", // assign list ID
      };
    });
    
    const initialDataRight: Item[] = [...Array(NUM_ITEMS / 2)].map((d, index) => {
      const backgroundColor = getColor(NUM_ITEMS / 2 + index);
      return {
        key: `right-item-${index}`,
        label: String(index) + "",
        height: 100,
        width: 60 + Math.random() * 40,
        backgroundColor,
        listId: "right", // assign list ID
      };
    });
    
    export default function App() {
      const [leftData, setLeftData] = useState(initialDataLeft);
      const [rightData, setRightData] = useState(initialDataRight);
    
      const renderItem = ({ item, drag, isActive }: RenderItemParams<Item>) => {
        return (
          <ScaleDecorator>
            <TouchableOpacity
              onLongPress={drag}
              disabled={isActive}
              style={[
                styles.rowItem,
                { backgroundColor: isActive ? "red" : item.backgroundColor },
              ]}
            >
              <Text style={styles.text}>{item.label}</Text>
            </TouchableOpacity>
          </ScaleDecorator>
        );
      };
    
      const handleDragEnd = (fromListId, toListId, item) => {
        const fromList = (fromListId === "left") ? leftData : rightData;
        const toList = (toListId === "left") ? setLeftData : setRightData;
    
        const updatedFromList = fromList.filter((i) => i.key !== item.key);
        toList((prevData) => [...prevData, item]);
      };
    
      // Custom DraggableFlatList for each list
      const LeftFlatList = () => (
        <DraggableFlatList
          data={leftData}
          keyExtractor={(item) => item.key}
          renderItem={renderItem}
          onDragEnd={({ data }) => {
            handleDragEnd("left", "right", data[0]); // assuming only 1 item is dragged
            setLeftData(data);
          }}
        />
      );
    
      const RightFlatList = () => (
        <DraggableFlatList
          data={rightData}
          keyExtractor={(item) => item.key}
          renderItem={renderItem}
          onDragEnd={({ data }) => {
            handleDragEnd("right", "left", data[0]); // assuming only 1 item is dragged
            setRightData(data);
          }}
        />
      );
    
      return (
        <View style={styles.container}>
          <View style={styles.listContainer}>
            <LeftFlatList />
          </View>
          <View style={styles.listContainer}>
            <RightFlatList />
          </View>
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      rowItem: {
        height: 100,
        width: 100,
        alignItems: "center",
        justifyContent: "center",
      },
      text: {
        color: "white",
        fontSize: 24,
        fontWeight: "bold",
        textAlign: "center",
      },
    });
    
    

    for more details: Visit documentation

    Login or Signup to reply.
  2. 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;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search