React Native 如何实现FlatList间元素拖拽、列表重排及拖拽删除功能
React Native 跨容器拖拽+列表重排序实现方案
库选型建议
放弃react-native-draggable,该库的实现逻辑限制了拖拽元素只能在父容器范围内移动,无法满足跨FlatList拖拽的需求。推荐使用RN生态主流的手势动画组合:
react-native-gesture-handler:负责原生级手势识别,性能远好于JS层手势实现react-native-reanimated:负责拖拽动画的原生线程渲染,避免拖拽卡顿react-native-draggable-flatlist:基于前两个库封装的可拖拽重排序FlatList组件,开箱即用
各需求实现逻辑
- 拖拽元素出FlatList范围:拖拽触发时将橙色圆点切换为根视图下的绝对定位元素,用共享值同步拖拽坐标,不受FlatList的overflow属性限制,可拖动到屏幕任意位置
- FlatList列表项重排序:直接使用
react-native-draggable-flatlist组件,仅需配置数据源、渲染项、拖拽结束回调三个核心参数即可实现列表项拖拽重排序 - 拖拽到垃圾桶删除:提前测量垃圾桶区域的屏幕坐标范围,拖拽结束后判断当前拖拽元素的坐标是否落在该范围,命中则从数据源中删除对应项
核心代码示例
import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import Animated, { useSharedValue, useAnimatedStyle } from 'react-native-reanimated'; import DraggableFlatList from 'react-native-draggable-flatlist'; const App = () => { const [positionList, setPositionList] = useState([]); const dragX = useSharedValue(0); const dragY = useSharedValue(0); const isDragging = useSharedValue(false); const activeItem = useSharedValue(null); let trashLayout = {x:0,y:0,width:0,height:0}; // 拖拽手势配置 const panGesture = Gesture.Pan() .onStart((_, item) => { isDragging.value = true; activeItem.value = item; }) .onUpdate((event) => { dragX.value = event.absoluteX; dragY.value = event.absoluteY; }) .onEnd(() => { // 校验是否落在垃圾桶区域 if (dragX.value > trashLayout.x && dragX.value < trashLayout.x + trashLayout.width && dragY.value > trashLayout.y && dragY.value < trashLayout.y + trashLayout.height) { setPositionList(prev => prev.filter(i => i.id !== activeItem.value.id)); } // 校验是否落在时间线区域,执行添加逻辑 // 重置状态 dragX.value = 0; dragY.value = 0; isDragging.value = false; activeItem.value = null; }); return ( <View style={{flex: 1}}> {/* 可重排序的positions列表 */} <DraggableFlatList data={positionList} onDragEnd={({data}) => setPositionList(data)} renderItem={({item, drag}) => ( <GestureDetector gesture={panGesture}> <Animated.View> {/* 列表项内容 */} <View style={{width: 20, height: 20, backgroundColor: 'orange', borderRadius: 10}} /> </Animated.View> </GestureDetector> )} /> {/* 时间线区域 */} <View /> {/* 垃圾桶区域,用onLayout获取坐标 */} <View onLayout={(e) => trashLayout = e.nativeEvent.layout} /> {/* 全局悬浮的拖拽圆点,拖拽时显示 */} {isDragging.value && ( <Animated.View style={[{ position: 'absolute', left: dragX.value - 10, top: dragY.value - 10, width: 20, height: 20, backgroundColor: 'orange', borderRadius: 10, zIndex: 999 }]} /> )} </View> ) }
注意事项
安装依赖后需要按照官方指引配置原生工程:iOS端执行pod install,Android端修改MainActivity文件注册手势处理器,避免手势无响应问题。
内容的提问来源于stack exchange,提问作者Furkan Ergün
相关产品推荐
相关产品推荐

