原文链接:www.jianshu.com

只需完成个人实名注册,即可获得腾讯云免费套餐!云服务器CVM、云数据库 MYSQL、文件存储 CFS.....应有尽有!https://cloud.tencent.com/act/free

话不多说,先上效果图


普通view拖拽效果 
TableView拖拽效果
CollectionView效果
muti-touch效果
多app交互

世界上最大的男性交友网站有demo

一.Tips:你必须要知道的概念

1. Drag 和 Drop 是什么呢?
  • 一种以图形展现的方式把数据从一个 app 移动或拷贝到另一个 app(仅限iPad),或者在程序内部进行
  • 充分利用了 iOS11 中新的文件系统,只有在请求数据的时候才会去移动数据,而且保证只传输需要的数据
  • 通过异步的方式进行传输,这样就不会阻塞runloop,从而保证在传输数据的时候用户也有一个顺畅的交互体验


drag和drop的基本交互图和支持的控件

2. 安全性:
  • 拖拽复制的过程不像剪切板那样,而是保证数据只对目标app可见
  • 提供数据源的app可以限制本身的数据源只可在本 app 或者 公司组app 之间有权限使用,当然也可以开放于所有 app,也支持企业用户的管理配置
3. dragSession 的过程
  • Lift:用户长按 item,item 脱离屏幕
  • Drag :用户开始拖拽,此时可进行 自定义视图预览、添加其他item添加内容、悬停进行导航(即iPad 中打开别的app)
  • Set Down :此时用户无非想进行两种操作:取消拖拽 或者 在当前手指离开的位置对 item 进行 drop 操作
  • Data Transfer :目标app 会向 源app 进行数据请求
  • 这些都是围绕交互这一概念构造的:即类似手势识别器的概念,接收到用户的操作后,进行view层级的改变

4. Others
  • 需要给用户提供 muti-touch 的使用,这一点也是为了支持企业用户的管理配置(比如一个手指选中一段文字,长按其处于lifting状态,另外一个手指选中若干张图片,然后打开邮件,把文字和图片放进邮件,视觉反馈是及时的,动画效果也很棒)


iPad 可实现的功能还是很丰富的

二、以CollectionView 为例,讲一下整个拖拽的api使用情况

在API设计方面,分为两个步骤:Drag 和 Drop,对应着两套协议 UICollectionViewDragDelegate 和
UICollectionViewDropDelegate,因此在创建 CollectionView 的时候要增加以下代码:

- (void)buildCollectionView {_collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];[_collectionView registerClass:[WPFImageCollectionViewCell class] forCellWithReuseIdentifier:imageCellIdentifier];_collectionView.delegate = self;_collectionView.dataSource = self;// 设置代理对象_collectionView.dragDelegate = self;_collectionView.dropDelegate = self;_collectionView.dragInteractionEnabled = YES;_collectionView.reorderingCadence = UICollectionViewReorderingCadenceImmediate;_collectionView.springLoaded = YES;_collectionView.backgroundColor = [UIColor whiteColor];
}
1. 创建CollectionView注意点总结:
  • dragInteractionEnabled 属性在 iPad 上默认是YES,在 iPhone 默认是 NO,只有设置为 YES 才可以进行 drag 操作

  • reorderingCadence (重排序节奏)可以调节集合视图重排序的响应性。 是 CollectionView 独有的属性(相对于UITableView),因为 其独有的二维网格的布局,因此在重新排序的过程中有时候会发生元素回流了,有时候只是移动到别的位置,不想要这样的效果,就可以修改这个属性改变其相应性

    • UICollectionViewReorderingCadenceImmediate:默认值,当开始移动的时候就立即回流集合视图布局,可以理解为实时的重新排序
    • UICollectionViewReorderingCadenceFast:如果你快速移动,CollectionView 不会立即重新布局,只有在停止移动的时候才会重新布局
    • UICollectionViewReorderingCadenceSlow:停止移动再过一会儿才会开始回流,重新布局
  • springLoaded :弹簧加载是一种导航和激活控件的方式,在整个系统中,当处于 dragSession 的时候,只要悬浮在cell上面,就会高亮,然后就会激活

    • UITableView 和 UICollectionView 都可以使用该方式加载,因为他们都遵守 UISpringLoadedInteractionSupporting 协议
    • 当用户在单元格使用弹性加载时,我们要选择 CollectionView 或tableView 中的 item 或cell
    • 使用 - (BOOL)collectionView:shouldSpringLoadItemAtIndexPath:withContext:来自定义也是可以的
  • collectionView:itemsForAddingToDragSession: atIndexPath: :该方法是muti-touch对应的方法

    • 当接收到添加item响应时,会调用该方法向已经存在的drag会话中添加item
    • 如果需要,可以使用提供的点(在集合视图的坐标空间中)进行其他命中测试。
    • 如果该方法未实现,或返回空数组,则不会将任何 item 添加到拖动,手势也会正常的响应
- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForAddingToDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point {NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.dataSource[indexPath.item]];UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];return @[item];
}


再放一遍这个效果图

2. UICollectionViewDragDelegate(初始化和自定义拖动方法)
  • collectionView: itemsForBeginningDragSession:atIndexPath:提供一个 给定 indexPath 的可进行 drag 操作的 item(类似 hitTest: 方法周到该响应的view )如果返回 nil,则不会发生任何拖拽事件

由于是返回一个数组,因此可以根据自己的需求来实现该方法:比如拖拽一个item,就可以把该组的所有 item 放进 dragSession 中,右上角会有小蓝圈圈显示个数(但是这种情况下要对数组进行重新排序,因为数组中的最后一个元素会成为Lift 操作中的最上面的一个元素,排序后可以让最先进入dragSession的item放在lift效果的最前面)

- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForBeginningDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath {NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.dataSource[indexPath.item]];UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];self.dragIndexPath = indexPath;return @[item];
}

  • collectionView:dragPreviewParametersForItemAtIndexPath:允许对从取消或返回到 CollectionView 的 item 使用自定义预览,如果该方法没有实现或者返回nil,那么整个 cell 将用于预览

    • UIDragPreviewParameters 有两个属性:

      • backgroundColor 设置背景颜色,因为有的视图本身就是半透明的,添加背景色视觉效果更好
      • visiblePath设置视图的可见区域,比如可以自定义为圆角矩形或图中的某一块区域等,但是要注意裁剪的Rect 在目标视图中必须要有意义;该属性也要标记一下center方便进行定位


裁剪图中的某一块区域
选取的区域也可以大于这张图,实现添加相框的效果 
再高级的功能可以实现目标区域内添加多个rect到dragSession

- (nullable UIDragPreviewParameters *)collectionView:(UICollectionView *)collectionView dragPreviewParametersForItemAtIndexPath:(NSIndexPath *)indexPath {// 可以在该方法内使用 贝塞尔曲线 对单元格的一个具体区域进行裁剪UIDragPreviewParameters *parameters = [[UIDragPreviewParameters alloc] init];CGFloat previewLength = self.flowLayout.itemSize.width;CGRect rect = CGRectMake(0, 0, previewLength, previewLength);parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5];parameters.backgroundColor = [UIColor clearColor];return parameters;
}
  • 还有一些对于 drag 生命周期对应的回调方法,可以在这些方法里添加各种动画效果
/* 当 lift animation 完成之后开始拖拽之前会调用该方法* 该方法肯定会对应着 -collectionView:dragSessionDidEnd: 的调用*/
- (void)collectionView:(UICollectionView *)collectionView dragSessionWillBegin:(id<UIDragSession>)session {NSLog(@"dragSessionWillBegin --> drag 会话将要开始");
}// 拖拽结束的时候会调用该方法
- (void)collectionView:(UICollectionView *)collectionView dragSessionDidEnd:(id<UIDragSession>)session {NSLog(@"dragSessionDidEnd --> drag 会话已经结束");
}

当然也可以在这些方法里面设置自定义的dragPreview,比如 iPad 中原生的通讯图、地图所展现的功能


在 dragSessionWillBegin 方法里面自定义 preview 视图

3. UICollectionViewDropDelegate(迁移数据和自定义释放动画)


Drop手势的流程图

  • collectionView:performDropWithCoordinator: 方法使用 dropCoordinator 去置顶如果处理当前 drop 会话的item 到指定的最终位置, 同时也会根据drop item返回的数据更新数据源

    • 当用户开始进行 drop 操作的时候会调用这个方法
    • 如果该方法不做任何事,将会执行默认的动画
    • 注意:只有在这个方法中才可以请求到数据
    • 请求的方式是异步的,因此不要阻止数据的传输,如果阻止时间过长,就不清楚数据要多久才能到达,系统甚至可能会kill掉你的应用
- (void)collectionView:(UICollectionView *)collectionView performDropWithCoordinator:(id<UICollectionViewDropCoordinator>)coordinator {NSIndexPath *destinationIndexPath = coordinator.destinationIndexPath;UIDragItem *dragItem = coordinator.items.firstObject.dragItem;UIImage *image = self.dataSource[self.dragIndexPath.row];// 如果开始拖拽的 indexPath 和 要释放的目标 indexPath 一致,就不做处理if (self.dragIndexPath.section == destinationIndexPath.section && self.dragIndexPath.row == destinationIndexPath.row) {return;}// 更新 CollectionView[collectionView performBatchUpdates:^{// 目标 cell 换位置[self.dataSource removeObjectAtIndex:self.dragIndexPath.item];[self.dataSource insertObject:image atIndex:destinationIndexPath.item];[collectionView moveItemAtIndexPath:self.dragIndexPath toIndexPath:destinationIndexPath];} completion:^(BOOL finished) {}];[coordinator dropItem:dragItem toItemAtIndexPath:destinationIndexPath];
}
  • collectionView: dropSessionDidUpdate: withDestinationIndexPath: 该方法是提供释放方案的方法,虽然是optional,但是最好实现

    • 当 跟踪 drop 行为在 tableView 空间坐标区域内部时会频繁调用(因此要尽量减少这个方法的工作量,否则帧率就会降低)
    • 当drop手势在某个section末端的时候,传递的目标索引路径还不存在(此时 indexPath 等于 该 section 的行数),这时候会追加到该section 的末尾
    • 在某些情况下,目标索引路径可能为空(比如拖到一个没有cell的空白区域)
    • 请注意,在某些情况下,你的建议可能不被系统所允许,此时系统将执行不同的建议
    • 你可以通过 -[session locationInView:] 做你自己的命中测试
    • UICollectionViewDropIntent对应的三个枚举值
      • UICollectionViewDropIntentUnspecified 将会接收drop,但是具体的位置要稍后才能确定;不会开启一个缺口,可以通过添加视觉效果给用户传达这一信息
      • UICollectionViewDropIntentInsertAtDestinationIndexPathdrop将会被插入到目标索引中;将会打开一个缺口,模拟最后释放后的布局
      • UICollectionViewDropIntentInsertIntoDestinationIndexPathdrop 将会释放在目标索引路径,比如该cell是一个容器(集合),此时不会像

史上第二走心的 iOS11-Drag Drop 教程相关推荐

  1. 史上第二走心的 iOS11 Drag Drop 教程

    2017.11.02 话不多说,先上效果图 世界上最大的男性交友网站有demo 一.Tips:你必须要知道的概念 1. Drag 和 Drop 是什么呢? 一种以图形展现的方式把数据从一个 app 移 ...

  2. 史上最走心的Webpack4.0中级教程——配置之外你应该知道事

    [摘要] <webpack4.0各个击破系列>适合不满足于只会配置webpack但一时间又看不懂源码的中级读者.我没法保证这个系列是最好的,但至少能保证每一篇博文都跟那些Ctrl+C和Ct ...

  3. 帝企鹅日记(史上第二受欢迎记录片 老少皆宜的冰雪童话)

    帝企鹅日记(史上第二受欢迎记录片 老少皆宜的冰雪童话) 编辑推荐 - Editors' Choice 法国的生物记录电影以其独特而精妙的拍摄方式,不仅营造出诗意盎然的绝美画面,也为人们提供了另一种观看 ...

  4. 史上最详细的Android Studio系列教程四--Gradle基础

    史上最详细的Android Studio系列教程四--Gradle基础 转载于:https://www.cnblogs.com/zhujiabin/p/5125917.html

  5. linux bios设置界面,BIOS怎么设置 史上最详细的bios设置图解教程

    BIOS怎么设置?下面百事网小编就为大家带来史上最详细的bios设置图解教程. 一 进入BIOS设置程序通常有以下三种方法 1.开机启动时按热键(最通用也最常用) 在开机时按下特定的热键可以进入BIO ...

  6. 史上最纯净的电脑系统重装教程,怕你不会,手把手教你,会了支持一下老学长!

    史上最纯净的电脑系统重装教程 各位朋友大家好,我是贪玩老学长,也就是你们所看到的文章发帖UP主.很荣幸,我已经完成了我本科4年,硕士3年的求学生涯,于2021年7月入职,致力于给大家分享电脑知识相关的 ...

  7. 史上最全面的python学生管理系统教程(二)

    目录 序言 sqlite使用教程 python sqlite使用教程 数据库构造 学生信息表结构: 教师信息表结构: 课程成绩表结构: 教师添加课程: 学生表连接课程成绩表: 数据库语句了解 sqli ...

  8. 史上最经典的IT入门学习教程DVD光盘免费领!

    史上最经典的IT入门学习教程DVD光盘免费领! http://user.qzone.qq.com/1679806262/blog/1395540727

  9. 史上最简单的wordpress迁移搬家教程

    当我们的wordpress网站需要换服务器或者域名时,又或者我们在本地使用做好了wordpress网站需要上线时,都需要用到wordpress迁移搬家技术.我网上也搜了很多,什么又要改数据什么的比较麻 ...

最新文章

  1. SSM-Spring-19:Spring中JdbcTemplate
  2. c语言 自动测试,C语言测试。自己实现scandir 函数
  3. 解决延迟有 Wi-Fi 6 就够了!
  4. nullnulle-人事管理系统-人事档案-变更管理-人员合同变更
  5. Greedy Sequence(2019南京icpc网络预选赛)主席树求区间小于k的最大值
  6. 【NC54 三数之和】(待整理)
  7. 就业阶段-java语言进价_day06
  8. 自旋锁和互斥锁实例_多线程编程之自旋锁
  9. mysql uroot p 报错,MySQL链接错误集。
  10. c语言二级考试程序设计题的做题步骤,计算机二级C语言上机考试操作步骤与流程.doc...
  11. Android网络编程之——文件断点下载(暂停/继续/重新下载)
  12. CentOS下IOZone编译安装
  13. win系统磁盘管理知识
  14. 禅与 JavaScript 编程艺术, Zen and The Art of JavaScript Programming
  15. twm图形模式以及恢复
  16. 字节跳动CVPR 2023论文精选来啦(内含一批图像生成新研究)
  17. 【愚公系列】2023年05月 网络安全高级班 067.WEB渗透与安全(Havij实战-SQL自动化注入)
  18. nexus私服知识概括
  19. 【HTML】HTML网页设计----模仿汉服前端设计
  20. 谈谈学习 - 费曼技巧,以教促学的好方法

热门文章

  1. wait跟sleep的区别
  2. Android13.9.15
  3. show-busy-java-threads查找CPU占用高
  4. expires与etag控制页面缓存的优先级
  5. 详解.NET的RAD功能
  6. 深入讲解 ASP+ 验证
  7. 以安装PyTorch为例说明Anaconda在Windows/Linux上的使用
  8. Windows7 64bit VS2013 Caffe train MNIST操作步骤
  9. oracle cusor游标,ORACLE CURSOR 游标详解
  10. matplotlib 散点图和折线图画在一起_使用matplotlib.pyplot画折线图