You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native中实现两个FlatList间的拖拽功能?

两个FlatList间拖拽功能实现方案

核心思路

通过封装好的拖拽库或原生手势API,实现跨列表的拖拽识别与数据源同步,核心是处理拖拽结束时的源列表数据移除、目标列表数据插入逻辑。

推荐简化实现库:react-native-draggable-flatlist

这个库专门针对FlatList拖拽场景做了封装,能快速实现跨列表拖拽需求,步骤如下:

1. 安装依赖

npm install react-native-draggable-flatlist
# 或使用yarn
yarn add react-native-draggable-flatlist

2. 完整实现代码

import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import DraggableFlatList, {
  RenderItemParams,
  DragEndParams,
} from 'react-native-draggable-flatlist';

// 定义列表项数据类型
type ListItem = {
  key: string;
  content: string;
};

export default function CrossListDragDemo() {
  // 初始化两个列表的数据源
  const [leftList, setLeftList] = useState<ListItem[]>([
    { key: 'l1', content: '左侧列表项1' },
    { key: 'l2', content: '左侧列表项2' },
    { key: 'l3', content: '左侧列表项3' },
  ]);
  const [rightList, setRightList] = useState<ListItem[]>([
    { key: 'r1', content: '右侧列表项1' },
    { key: 'r2', content: '右侧列表项2' },
  ]);

  // 渲染单个列表项
  const renderListItem = ({ item, drag, isActive }: RenderItemParams<ListItem>) => (
    <View style={[styles.itemContainer, isActive && styles.activeItem]}>
      <Text onPress={drag} style={styles.itemText}>{item.content}</Text>
    </View>
  );

  // 处理拖拽结束事件
  const handleDragFinish = ({ data, from, to }: DragEndParams<ListItem>, sourceListKey: string) => {
    // 判断是否是跨列表拖拽
    if (sourceListKey !== to.list) {
      // 从源列表移除拖拽项
      const sourceData = sourceListKey === 'left' ? leftList : rightList;
      const updatedSource = sourceData.filter((_, idx) => idx !== from);
      // 向目标列表插入拖拽项
      const targetData = to.list === 'left' ? leftList : rightList;
      const updatedTarget = [
        ...targetData.slice(0, to.index),
        data[from],
        ...targetData.slice(to.index),
      ];
      // 更新对应列表的状态
      if (sourceListKey === 'left') {
        setLeftList(updatedSource);
        setRightList(updatedTarget);
      } else {
        setRightList(updatedSource);
        setLeftList(updatedTarget);
      }
    } else {
      // 同列表拖拽,仅更新排序
      if (sourceListKey === 'left') setLeftList(data);
      else setRightList(data);
    }
  };

  return (
    <View style={styles.pageContainer}>
      <View style={styles.listWrapper}>
        <Text style={styles.listTitle}>左侧列表</Text>
        <DraggableFlatList
          data={leftList}
          renderItem={renderListItem}
          keyExtractor={(item) => item.key}
          onDragEnd={(params) => handleDragFinish(params, 'left')}
          listKey="left"
        />
      </View>
      <View style={styles.listWrapper}>
        <Text style={styles.listTitle}>右侧列表</Text>
        <DraggableFlatList
          data={rightList}
          renderItem={renderListItem}
          keyExtractor={(item) => item.key}
          onDragEnd={(params) => handleDragFinish(params, 'right')}
          listKey="right"
        />
      </View>
    </View>
  );
}

// 样式定义
const styles = StyleSheet.create({
  pageContainer: {
    flex: 1,
    flexDirection: 'row',
    padding: 16,
    gap: 16,
  },
  listWrapper: {
    flex: 1,
  },
  listTitle: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 12,
  },
  itemContainer: {
    backgroundColor: '#f5f5f5',
    padding: 14,
    borderRadius: 8,
    marginBottom: 8,
  },
  activeItem: {
    backgroundColor: '#e0e0e0',
  },
  itemText: {
    fontSize: 16,
  },
});

3. 关键逻辑说明

  • 用listKey标记两个列表,在拖拽结束时区分来源与目标列表
  • 跨列表拖拽时,分别执行“源列表移除项”和“目标列表插入项”的操作
  • 同列表拖拽则直接更新对应列表的排序

原生手动实现思路(无第三方库)

如果不想依赖第三方库,可基于react-native-gesture-handler和react-native-reanimated实现:

  • 给每个列表项绑定PanGestureHandler拖拽手势
  • 拖拽过程中生成悬浮的拖拽预览视图
  • 通过监听目标列表的布局区域,判断拖拽是否进入目标范围
  • 释放手势时,更新两个列表的数据源

原生实现代码量较大,适合需要高度自定义拖拽交互的场景,普通需求更推荐使用封装好的库。

内容的提问来源于stack exchange,提问作者Jaydip Ramani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:40:16