很多人可能都做过 html 的拖动,但是估计做 react-native 的拖动的人就不是特别多了。这里分享一下之前做的一个组件的设计思路。后面主要写了一些伪代码,主要是提供一个写这个组件的思路,具体的源码可以查看下面这个地址。
源码地址:
react-native-draggable-grid
关键 api
在讲关键算法之前先说一下需要用的几个关键方法和参数
react-native 提供了一个 PanResponder
用于识别手势操作
onPanResponderMove
onPanResponderMove: (event, gestureState) => {}
gestureState
x0
当响应器产生时的屏幕横坐标, 响应器一直没释放的话,这个值是一直不变的y0
当响应器产生时的屏幕纵坐标,响应器一直没释放的话,这个值是一直不变的moveX
最近一次移动时,手指在屏幕上相对于屏幕的x坐标,屏幕最左上角坐标为0,0moveY
最近一次移动时,手指在屏幕上相对于屏幕的y坐标,屏幕最左上角坐标为0,0
开始
我们这个组件有一个需要注意的是,组件会被限制在只能在一定的区域内拖动,不能超过这个区域。
第一步
首先我们需要在组件构造函数里实例化一个 panResponder
1 |
|
第二步
将 GestureResponderHandlers
赋给对应的组件,为了较简单的去定位元素,我们选择了用 absolute
定位。
1 |
|
第三步
这一步主要是设置 currentPosition.setOffset({x,y,});
, 这个的作用是,以后每次我们调用 setValue 的时候都会调用在其基础上加上x,y,后面会详细讲解为什么要这样设置。
1 | private onStartDrag(nativeEvent:GestureResponderEvent, gestureState:PanResponderGestureState) { |
第四步
这一步主要是计算出手指拖动的位置,然后重新设置 view 的left和right,后面详细讲解一下整个的计算思路
1 | private onHandMove(nativeEvent:GestureResponderEvent, gestureState:PanResponderGestureState) { |
我们来看一下我们从下面这个位置,移动到上面这个这个位置是如何计算出新的位置的坐标。新的y等于 y - (moveY1 - moveY2) = y -moveY1 + moveY2,我们onStartDrag的setOffset做的其实就是先把y - moveY1 这部分算出来缓存起来。后面我们只需要直接加上最新moveY即为最终结果。
现在再来看一下如何把组件限制在一定区域内移动:
最上边界
我们先看纵坐标我们能移动到的最上面的位置。y的值最小为0,即要控制offsetY + moveY >= 0
如果组件移动超过了限制区域,newY = moveY + offsetY,newY 是个负值,此时我们需要把newY向下偏移到0
最下边界
要控制vie移动的最下面区域之上,我们需要控制 offsetY + moveY <= parentHeight - blockHeight
如果区域超出了最下边的底线,超出值等于 (offsetY + moveY - (parentHeight - blockHeight)), 如果超出的话这个值为正值,我们的offsetY + moveY需要减去这个值,不超出的话则是负值
偏移算法
上面接触到最上边界和最下边界同时只会发生一个,我们可以通过修正offsetY + moveY来达到把y限制在一定区域内。
1 | // 上偏移调整值 |
x 的偏移调整也是同理。
最后
最后就是在手指释放的时候将 panResponderCapture
设置回 false
1 |
|
组件还有涉及到数据同步,定位,排序等算法,这里就不做细讲了,有兴趣的可以去看源码研究一下。-