最近接到一个交互比较复杂的需求,大致需求是要实现拖拽排序如下图所示。长按可以选择某个美食可以进行拖拽,当拖拽到某个其他美食上面时,可以放到对应美食前面。
开始是想找下网上现有的库资源
上面两个库虽然都支持了列表的拖拽排序,但是对于我自己的需求,还是有不同的,我的列表上面首先是展示的美食卡片,接着每个卡片里面有对应的美食列表,所以卡片的头部和底部是不可以拖拽的,这也导致上面的库并不是适合我的需求,接下来就是自己研究开发一个了。 首先,说的RN的手势处理,虽然官方也提供了对应的手势处理 api,但是做点简单的操作还可以,遇到手势复杂的地方,就无计可施了。所幸第三方库 react-native-gesture-handler 提供了更加强大的手势处理。
一。我们首先分析下,需要的手势,长按和移动。我们可以使用 react-native-gesture-handler 提供的 GestureDetector 手势检测 api 并组合长按和移送手势处理。类似如下
//长按手势处理
const longPress = Gesture.LongPress().onStart((e)=>{
}).minDuration(500);
//处理滑动和抬起手势
const pan = Gesture.Pan().onUpdate((e) => {
}).onTouchesUp((e)=>{ //停止拖拽
}).activateAfterLongPress(500);
//手势合并
const composed = Gesture.Simultaneous(longPress, pan);
return(
<GestureDetector gesture={composed}>
</GestureDetector>
)
二。接着我们为了判断当前被拖拽的美食元素移动到了哪个美食元素上面,还需要知道列表元素中每个美食元素的 y 坐标,这个我们可以借助 RN View 组件上面提供的 onLayout 方法,去计算每个卡片里面的每个美食元素的 y 坐标, 其实这个时候我们可以去固定每个美食卡片的头部高度和每个美食元素的高度,方便我们去计算。如下图所示
三。接着我们怎么处理上下的自动滚动效果呢。这这里我是用了定时器和 ScrollView 上面的 scrollTo 方法去滚动,大致代码如下。
const scrollAuto = (dy) => {
stopScrollAuto();
scrollInterval = setInterval(()=>{
let y = ScrollY + dy; //判断是否超出滚动最大距离
if(y > totalH - scrollViewH){
y = totalH - scrollViewH;
IsScroll = false;
stopScrollAuto();
}else if(y < 0 ){ //判断是否小于最小滚动距离
y = 0;
IsScroll = false;
stopScrollAuto();
}
scrollRef.current.scrollTo({
y: y,
animated: false,
})
}, SCROLL_INTERVAL);
}
由此上面三步即可实现我们想要的效果,我们还可以做更多的优化。