写在前面
- 最近不忙,看见一个好玩,而且很实用,既然闲来无事,就自己动手做出来,coder. 感觉还不错就是界面比较丑陋了点,不过没关系明白原理就好了!爱生活,爱钻研,爱分享
- github 地址https://github.com/zyjian/EditCollectionViewCell
- 记得留下你的脚印哦
进入主题
-
首先我们还是先看看效果吧
QQ20180316-183625.gif
需求分析
- 类似今日头条首页的横向菜单,编辑,移动删除,都是可以的,这里我们做的是移动,删除也是同样的道理
- 步骤拆解: 给每个cell 添加长按手势,长按进入编辑状态,此时可以拖动当前cell 移动到想要调整的位置。
原理分析
- 主要是UIcollectionView 的一个方法的灵活使用:collectionView.moveItem(at: indexPathP, to: nextIndexPathP)
- 创建collectionView 并且构造数据源,这里是用的懒加载,注意这里我们使用的OC 的NSMutableArray,因为我们要使用exchange方法这样更简单
private var dataArray:NSMutableArray = {
var array:NSMutableArray = NSMutableArray.init()
for i in 0..<100 {
array.add("第\(i)个")
}
return array
}()
- 给cell 添加长按手势,并且将手势事件通过代理协议,传到viewController中
- 核心代码
extension ViewController:ItemCVCProtocl {
func itemCVClongPress(long: UILongPressGestureRecognizer) {
let cell:ItemCVC = long.view as! ItemCVC
if long.state == .began {//长按开始
//获取截图cell
snapshotView = cell.snapshotView(afterScreenUpdates: true)!
snapshotView?.center = cell.center
collectionView.addSubview(snapshotView!)
indexPathP = collectionView.indexPath(for: cell)!
originalCell = cell
originalCell.isHidden = true
startPoint = long.location(in: collectionView)
//colllectionViewAnimateCell(isgo: true)
}else if(long.state == .changed){
//移动
let tranx : CGFloat = long.location(ofTouch: 0, in: collectionView).x - startPoint.x
let trany : CGFloat = long.location(ofTouch: 0, in: collectionView).y - startPoint.y
snapshotView?.center = __CGPointApplyAffineTransform((snapshotView?.center)!, CGAffineTransform.init(translationX: tranx, y: trany))
//更新最新的开始移动
startPoint = long.location(ofTouch: 0, in: collectionView)
//计算截图和那个cell 交换
for cell in collectionView.visibleCells {
//跳过自己本身那个cell
if collectionView.indexPath(for: cell) == indexPathP {
continue;
}
//计算中心距
let space:CGFloat = sqrt(pow(snapshotView!.center.y-cell.center.y,2)+pow(snapshotView!.center.x-cell.center.x,2))
//如果相交一半且两个视图Y的绝对值小于高度的一半就移动
if space <= snapshotView!.bounds.width * 0.5
&& (fabs(snapshotView!.center.y - cell.center.y) <= snapshotView!.bounds.height * 0.5) {
nextIndexPathP = collectionView.indexPath(for: cell)!
if nextIndexPathP.item > indexPathP.item {
for i in indexPathP.item..<nextIndexPathP.item {
self.dataArray.exchangeObject(at: i, withObjectAt: i+1)
}
}else{
for i in (nextIndexPathP.item ..< indexPathP.item).reversed() {
self.dataArray.exchangeObject(at: i, withObjectAt: i - 1)
}
}
//移动
collectionView.moveItem(at: indexPathP, to: nextIndexPathP)
indexPathP = nextIndexPathP;
break;
}
}
}else if long.state == .ended {
snapshotView?.removeFromSuperview()
originalCell.isHidden = false
//colllectionViewAnimateCell(isgo: false)
}
}
}
- 注意:
- snapshotView = cell.snapshotView(afterScreenUpdates: true)! 截图这里是获取一个cell 副本,是两个不同的对象
//移动
let tranx : CGFloat = long.location(ofTouch: 0, in: collectionView).x - startPoint.x
let trany : CGFloat = long.location(ofTouch: 0, in: collectionView).y - startPoint.y
snapshotView?.center = __CGPointApplyAffineTransform((snapshotView?.center)!, CGAffineTransform.init(translationX: tranx, y: trany))
这里的 __CGPointApplyAffineTransform 创建一个平移的变化
__CGPointApplyAffineTransform((snapshotView?.center)!, CGAffineTransform.init(translationX: tranx, y: trany))
意思是相对于snapshotView?.center 这个点平移 X: tranx, y: trany,返回值是一个CGPoint
- 遍历collectionView中的cell(长按那个cell本身除外), 是否需要交换位置。
需要移动的条件
3.1 计算中心距 3.2 相交小于一半的时候
结尾寄语
艺术-海.png
如果你觉得不清晰的话,欢迎留言,互相学习共同进步!
最后再提醒一句文中的demo 在guhub地址是* github 地址https://github.com/zyjian/EditCollectionViewCell
网友评论