您现在的位置是:主页 > news > 新城镇建设官方网站/友情链接页面
新城镇建设官方网站/友情链接页面
admin2025/5/10 7:41:27【news】
简介新城镇建设官方网站,友情链接页面,中文wordpress主题,upyun wordpress最近由于业务需求需要实现一个功能需要实现图片的上传和排序和删除,在网上搜索了几款发现都需要固定列数,感觉不太友好,所以自己实现了一个可以不需要设定列数的排序,而且布局高度实现自适应。 源码链接 效果图对比(固定列数和自…
新城镇建设官方网站,友情链接页面,中文wordpress主题,upyun wordpress最近由于业务需求需要实现一个功能需要实现图片的上传和排序和删除,在网上搜索了几款发现都需要固定列数,感觉不太友好,所以自己实现了一个可以不需要设定列数的排序,而且布局高度实现自适应。 源码链接
效果图对比(固定列数和自…
最近由于业务需求需要实现一个功能需要实现图片的上传和排序和删除,在网上搜索了几款发现都需要固定列数,感觉不太友好,所以自己实现了一个可以不需要设定列数的排序,而且布局高度实现自适应。
源码链接
效果图对比(固定列数和自适应流布局)
[图片上传中...(iphone.jpg-9f7224-1533711885416-0)]
iphone.jpg
动态图
Demonstration.gif
实现
其实拖拽排序在大多数编程语言里已经有很多中三方插件可以使用,实现方法都差不多,而且例如Android和iOS或者现在的React-Native他们逻辑几乎是可以共用,你会写一个语言的拖拽排序,其他的都差不多。
梳理一下步骤
-
- 开始触发: 长按或触摸到达一定时间时触发开始排序,这时可以进行把被单机的item放大、透明、抖动动画。
-
- 开始滑动:
- (1) 被拖拽的item随着手指的滑动而滑动
- (2) 被拖动的item滑动到第x个时,item到x之间的item进行左滑右滑一个位置的动画。
-
- 松开手指:
- (1) 被拖拽的这个item通过四舍五入进入相应的位置。
- (2) 数据进行替换并重绘加布局矫正。
tip: 滑动逻辑,例如当你把index=1拖到index=3,不是将1和3替换(0,3,2,1,4),而是(0,3,1,2,4)这才是拖拽后结果,只将被拖拽的一个替换到要去的位置,其他的向前和向后移动
主要代码
// 触摸事件的监听
this._panResponder = PanResponder.create({onStartShouldSetPanResponder: (evt, gestureState) => this.props.sortable,onStartShouldSetPanResponderCapture: (evt, gestureState) => {this.isMovePanResponder = falsereturn false},// 接管触摸加滑动事件onMoveShouldSetPanResponder: (evt, gestureState) => this.isMovePanResponder,onMoveShouldSetPanResponderCapture: (evt, gestureState) => this.isMovePanResponder,onPanResponderGrant: (evt, gestureState) => {},onPanResponderMove: (evt, gestureState) => this.moveTouch(evt,gestureState),onPanResponderRelease: (evt, gestureState) => this.endTouch(evt),onPanResponderTerminationRequest: (evt, gestureState) => false,onShouldBlockNativeResponder: (evt, gestureState) => false,})//这里使用长按触发开发拖拽事件,其实开始是使用触摸一定时间后触发事件的,但和View的单机事件有冲突不好解决,所以选择了长按触发事件
startTouch(touchIndex) {// 接管滑动this.isMovePanResponder = true//if (this.measureTimeOut) clearTimeout(this.measureTimeOut)if (sortRefs.has(touchIndex)) {if (this.props.onDragStart) {this.props.onDragStart(touchIndex)}//变大和加透明Animated.timing(this.state.dataSource[touchIndex].scaleValue,{toValue: maxScale,duration: scaleDuration,}).start(()=>{// 备份被触摸的事件this.touchCurItem = {ref: sortRefs.get(touchIndex),index: touchIndex,// 记录之前的位置originLeft: this.state.dataSource[touchIndex].originLeft,originTop: this.state.dataSource[touchIndex].originTop,moveToIndex: touchIndex,}})}}//滑动
moveTouch (nativeEvent,gestureState) {if (this.touchCurItem) {let dx = gestureState.dxlet dy = gestureState.dyconst rowNum = parseInt(this.props.parentWidth/this.itemWidth);const maxWidth = this.props.parentWidth-this.itemWidthconst maxHeight = this.itemHeight*Math.ceil(this.state.dataSource.length/rowNum) - this.itemHeight//出界后取最大或最小值防止出界if (this.touchCurItem.originLeft + dx < 0) {dx = -this.touchCurItem.originLeft} else if (this.touchCurItem.originLeft + dx > maxWidth) {dx = maxWidth - this.touchCurItem.originLeft}if (this.touchCurItem.originTop + dy < 0) {dy = -this.touchCurItem.originTop} else if (this.touchCurItem.originTop + dy > maxHeight) {dy = maxHeight - this.touchCurItem.originTop}let left = this.touchCurItem.originLeft + dxlet top = this.touchCurItem.originTop + dy//置于最上层this.touchCurItem.ref.setNativeProps({style: {zIndex: touchZIndex,}})//滑动时刷新布局,这里直接刷新Animated的数字就可以进行局部刷新了
this.state.dataSource[this.touchCurItem.index].position.setValue({x: left,y: top,})let moveToIndex = 0let moveXNum = dx/this.itemWidthlet moveYNum = dy/this.itemHeightif (moveXNum > 0) {moveXNum = parseInt(moveXNum+0.5)} else if (moveXNum < 0) {moveXNum = parseInt(moveXNum-0.5)}if (moveYNum > 0) {moveYNum = parseInt(moveYNum+0.5)} else if (moveYNum < 0) {moveYNum = parseInt(moveYNum-0.5)}moveToIndex = this.touchCurItem.index+moveXNum+moveYNum*rowNumif (moveToIndex > this.state.dataSource.length-1) moveToIndex = this.state.dataSource.length-1// 其他item向左和向右滑动if (this.touchCurItem.moveToIndex != moveToIndex ) {this.touchCurItem.moveToIndex = moveToIndexthis.state.dataSource.forEach((item,index)=>{let nextItem = nullif (index > this.touchCurItem.index && index <= moveToIndex) {nextItem = this.state.dataSource[index-1]} else if (index >= moveToIndex && index < this.touchCurItem.index) {nextItem = this.state.dataSource[index+1]} else if (index != this.touchCurItem.index &&(item.position.x._value != item.originLeft ||item.position.y._value != item.originTop)) {nextItem = this.state.dataSource[index]//有时前一个或者后一个数据有个动画差的原因无法回到正确位置,这里进行矫正} else if ((this.touchCurItem.index-moveToIndex > 0 && moveToIndex == index+1) ||(this.touchCurItem.index-moveToIndex < 0 && moveToIndex == index-1)) {nextItem = this.state.dataSource[index]}//需要滑动的就进行滑动动画if (nextItem != null) {Animated.timing(item.position,{toValue: {x: parseInt(nextItem.originLeft+0.5),y: parseInt(nextItem.originTop+0.5)},duration: slideDuration,easing: Easing.out(Easing.quad),}).start()}})}}}//触摸事件endTouch (nativeEvent) {//clearif (this.measureTimeOut) clearTimeout(this.measureTimeOut)if (this.touchCurItem) {if (this.props.onDragEnd) {this.props.onDragEnd(this.touchCurItem.index,this.touchCurItem.moveToIndex)}//this.state.dataSource[this.touchCurItem.index].scaleValue.setValue(1)Animated.timing(this.state.dataSource[this.touchCurItem.index].scaleValue,{toValue: 1,duration: scaleDuration,}).start()this.touchCurItem.ref.setNativeProps({style: {zIndex: defaultZIndex,}})this.changePosition(this.touchCurItem.index,this.touchCurItem.moveToIndex)this.touchCurItem = null}}//刷新数据changePosition(startIndex,endIndex) {if (startIndex == endIndex) {const curItem = this.state.dataSource[startIndex]this.state.dataSource[startIndex].position.setValue({x: parseInt(curItem.originLeft+0.5),y: parseInt(curItem.originTop+0.5),})return;}let isCommon = trueif (startIndex > endIndex) {isCommon = falselet tempIndex = startIndexstartIndex = endIndexendIndex = tempIndex}const newDataSource = [...this.state.dataSource].map((item,index)=>{let newIndex = nullif (isCommon) {if (endIndex > index && index >= startIndex) {newIndex = index+1} else if (endIndex == index) {newIndex = startIndex}} else {if (endIndex >= index && index > startIndex) {newIndex = index-1} else if (startIndex == index) {newIndex = endIndex}}if (newIndex != null) {const newItem = {...this.state.dataSource[newIndex]}newItem.originLeft = item.originLeftnewItem.originTop = item.originTopnewItem.position = new Animated.ValueXY({x: parseInt(item.originLeft+0.5),y: parseInt(item.originTop+0.5),})item = newItem}return item})this.setState({dataSource: newDataSource},()=>{if (this.props.onDataChange) {this.props.onDataChange(this.getOriginalData())}//防止RN不绘制开头和结尾const startItem = this.state.dataSource[startIndex]this.state.dataSource[startIndex].position.setValue({x: parseInt(startItem.originLeft+0.5),y: parseInt(startItem.originTop+0.5),})const endItem = this.state.dataSource[endIndex]this.state.dataSource[endIndex].position.setValue({x: parseInt(endItem.originLeft+0.5),y: parseInt(endItem.originTop+0.5),})})}
后续会加上添加和删除Item渐变动画
源码链接
作者:mochixuan
链接:https://www.jianshu.com/p/5a42c9b34c83
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。