美文网首页iOS 大神之路iOS 技术文集ios开发笔记
实现collectionViewCell的移动(长按或者直接拖拽

实现collectionViewCell的移动(长按或者直接拖拽

作者: ZeroJ | 来源:发表于2016-05-02 15:57 被阅读5424次

最近在实现类似网易新闻的首页滑块的编辑效果: 长按后进入编辑界面, 然后可以通过拖拽实现cell的移动, 研究后发现两种实现方式: 第一种是直接利用系统提供的UICollectionView API实现移动, 不过只能在iOS9上面使用. 所以这里就介绍另外一种方式.

源码效果示例:


更新示例.gif

原理部分

  1. 添加一个长按手势到UICollectionView上
  2. 在这个手势的selector中通过获取到当前手势在collectionVIew的location来获取到一个indexPath, 如果这个indexPath是有效的, 那么就可以通过这个indexPath获取到对应的cell.
  3. 将获取到的cell截图, 然后将这个cell隐藏, 通过设置这个截图的frame使得这个截图跟随手指同步移动, 如果截图移动到了另外一个cell的位置, 则通过调用collectionView的方法将这两个cell交换位置, 同时需要更新collectionView的dataSource.

实现部分

  1. 在collectionView上添加一个长按手势
        let longGes = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressd(_:)))
        collectionView.addGestureRecognizer(longGes)

2 在selector中处理手势的响应

  • 2.1 获取当前手势的位置
        let location = ges.locationInView(self.collectionView)
  • 2.2 获取这个位置对应的在collectionView中的indexPath, 注意这个indexPath可能为nil(比如手指没有在cell的位置上时)
        // 当手指的位置不在collectionView的cell范围内时为nil
        let notSureIndexPath = self.collectionView.indexPathForItemAtPoint(location)
  • 2.3 通过当前手势的状态不同的处理
遍历状态.png
  • 2.3.1 case .Began 手势开始的时候
if let indexPath = notSureIndexPath { // 获取到的indexPath是有效的, 可以放心使用
                // a.
                currentIndexPath = indexPath
                // b. 
                let cell = collectionView.cellForItemAtIndexPath(indexPath)!
                // c.
                snapedImageView = getTheCellSnap(cell)
                
                deltaSize = CGSize(width: location.x - cell.frame.origin.x, height: location.y - cell.frame.origin.y)
                // d.
                snapedImageView.center = cell.center
                snapedImageView.transform = CGAffineTransformMakeScale(1.1, 1.1)
                // e.
                cell.alpha = 0.0
                // f.
                collectionView.addSubview(snapedImageView)
    }

a. 记录下当前的indexPath以便于在手指移动的过程中进入.Changed状态的时候使用
b. 通过这个indexPath获取到对应的cell
c. 获取到这个cell截图
d. 并且设置截图的初始位置
e. 隐藏当前的cell
f. 将截图添加到collectionView中

  • 2.3.2 case .Changed 手指在移动的时候
            // a. 
            if snapedImageView == nil { return }
            // b. 
            snapedImageView.frame.origin.x = location.x - deltaSize.width
            snapedImageView.frame.origin.y = location.y - deltaSize.height
            // c.
            if let newIndexPath = notSureIndexPath, let oldIndexPath = currentIndexPath {
                if newIndexPath != oldIndexPath && newIndexPath.section == oldIndexPath.section {// 只在同一组中移动
            // d.
                    collectionView.moveItemAtIndexPath(oldIndexPath, toIndexPath: newIndexPath)
                    // 更新dataSource

            // e. 
                    let cell = collectionView.cellForItemAtIndexPath(newIndexPath)
                    cell?.alpha = 0.0
            // f.
                    currentIndexPath = newIndexPath
                }
                
            }

a. 如果在began状态中没有获取到截图直接返回
b. 设置截图的位置, 以达到和手指同步移动
c. 如果新获取到的indexPath有效并且和原来的不相同
d. 移动cell, 更新dataSource
e. 设置新的cell的属性
f. 更新当前的indexPath

  • 2.3.3 case .End 手指离开屏幕的时候
            
            if let oldIndexPath = currentIndexPath {
                // a.
                let cell = collectionView.cellForItemAtIndexPath(oldIndexPath)!
                // b. 
                UIView.animateWithDuration(0.25, animations: {[unowned self] in
                        self.snapedImageView.transform = CGAffineTransformIdentity
                        self.snapedImageView.frame = cell.frame
                    }, completion: {[unowned self] (_) in
                        self.snapedImageView.removeFromSuperview()
                        self.snapedImageView = nil
                        self.currentIndexPath = nil
                        cell.alpha = 1.0
                        
                        
                })
            }

a. 获取到当前移动完成的cell
b. 使用动画移除截图并且设置当前的移动完成的cell的属性

到目前位置, 设置好collectionView的datasource和delegate方法后就可以实现以下的效果了

示例效果.gif

详细请移步源码, 如果您觉得有帮助,不妨给个star鼓励一下, 欢迎关注

相关文章

网友评论

  • Leaf_秋天:有 OC 版的吗
  • 阶梯: 第一种是直接利用系统提供的UICollectionView API实现移动, 不过只能在iOS9上面使用, 博主,为什么 iOS 9 以下不可以呢
  • 漂泊的飞鸟:大神,你的那个zjtagview的demo我看了,冒昧提一点建议,如果说错了请不要介意。里边交换exchangeobjectatindex方法没必要做循环,而且最外层的那个判断当前row和新row也不需要,直接交换元素就可以,我试过效果了。遍历后挨个交换和直接交换需要进行交换的两个集合元素应该是同一个效果吧。
  • First灬DKS:这种类型的有OC版的楼主? :smile:
    ZeroJ:@First灬DKS 应该不在那个demo里面,是个单独的,好像是ZJTagView
    First灬DKS:@ZeroJ 我下载了你的demo,但是没有找到这种可以移动的代码!
    ZeroJ:@First灬DKS 我记得github上面我上传过oc的
  • 曹晓龙:关于拖拽移动那一块, 如果cell 过多的话, 在拖拽期间 collectionView 不能滚动 手势冲突怎么解决?
  • 0c971754b468:这个效果在其他app上有看到,收藏了,谢谢博主
    ZeroJ:@JustaCoder 客气了,供参考
  • 9f94d02340f1:收藏了,谢谢分享!!
    ZeroJ:@JamesYea 供参考 :smiley:
  • 4a312d2d90b0:谢谢大神分享
    ZeroJ:@南枫lee :grin::grin:分享出来参考一下
  • 王大虾34:谢谢分享
    ZeroJ:@王大虾1号 :smiley:分享 给大家参考
  • 一滴水的世界:谢谢谢谢,刚好有这个需求
    ZeroJ:@一滴水的世界 很高兴,如果使用中出现问题请联系我 :smiley:
  • Zeke权:收下了
    ZeroJ:@熊格智障 欢迎收藏, 提供参考 :smiley:
  • 挂树上的骷髅怪:已经收藏.. 不过怎么录得会动的效果图呢? 求楼主解答.
    ZeroJ:@挂树上的骷髅怪 客气了, 直接百度就可以了
    挂树上的骷髅怪:@ZeroJ 哦哦 谢谢啊. 直接在app store里面下载吗?
    ZeroJ:@挂树上的骷髅怪 :smiley: 使用licecap软件就可以了
  • c4fc4484474c:楼主 已经给你star了 最后一个点击添加更多栏目 貌似有个bug 点击上面的按钮 下面的也会添加上去
    ZeroJ:@Mofaer文 已经解决了 :smiley:
    ZeroJ:@Mofaer文 对的,这个bug我明白,因为cell重用后会导致,我的初衷是希望分享给大家实现移动cell的东西,这个demo就偷懒实现了的:grin::grin:
  • 遛遛食:只有switch语言吗?有oc的吗?
    遛遛食:@ZeroJ 🙏
    ZeroJ:@遛遛食 OC版的请点这里 https://github.com/jasnig/ZJScrollPageView :smile: 最近才更新的
    ZeroJ:@遛遛食 不好意思, OC版的我没有去实现, 不过如果只是要实现cell的移动效果和上面是一样的思路, 但是要是想要使用里面的ScrollPageView来实现标题栏视图联动的效果就不支持OC的了, 如果需要可以看这里实现oc版的http://www.jianshu.com/p/b84f4dd96d0c, 或者到github上找找其他的
  • c4fc4484474c:楼主 下载了源码 怎么报错呀
    c4fc4484474c: @ZeroJ 已经改过来了
    ZeroJ:@Mofaer文 朋友,这个需要xcode7.3环境
    ZeroJ:@Mofaer文 :grin::grin:swift版本更新了
  • 旅行的光:有没有OC的实现方式。
    ZeroJ:@旅行的光 客气了, 共同学习
    旅行的光:@ZeroJ 非常感谢!:+1:
    ZeroJ:@旅行的光 不好意思, OC版的我没有去实现, 不过如果只是要实现cell的移动效果和上面是一样的思路, 但是要是想要使用里面的ScrollPageView来实现标题栏视图联动的效果就不支持OC的了, 如果需要可以看这里实现oc版的http://www.jianshu.com/p/b84f4dd96d0c, 或者到github上找找其他的 :smiley:
  • 那一片阳光:cellectionViewCell 标题是不是写错了 :joy:
    ZeroJ:@那一片阳光 :smile: :smile: 确实, 多谢提醒
  • 琪一可:mark 谢谢分享
    ZeroJ:分享出来大家一起学习 :smile:
  • xxttw:不错.收藏
    ZeroJ:@Unc1eWang 分享交流
  • jswift:谢谢分享, 每一篇都很有用
    jswift:@ZeroJ 学习到很多感谢 :grin:
    ZeroJ:@jswift :smile: 学习

本文标题:实现collectionViewCell的移动(长按或者直接拖拽

本文链接:https://www.haomeiwen.com/subject/uwokrttx.html