![](https://i-blog.csdnimg.cn/blog_migrate/3fb32d26c648bc3da506586423dd8a96.png)
随着iOS-11的发布,Apple在UITableView
和UICollectionView
引入了拖放功能,该拖放 UICollectionView
具有专门用于交互概念(类似于手势)的专用API。
表格视图和集合视图具有相似的API,以支持拖放,但有一些细微差别。
iPhone和iPad均支持拖放。 在iPad上,用户可以拖放多个应用程序。 但对于iPhone,此支持仅在单个应用程序中提供。
我们将讨论拖放在集合视图中的工作方式,同样适用于表格视图。 我将在需要的地方指出表视图的差异。 所以不用担心。 您将使它同时适用于集合视图和表视图。
让我们开始吧🚀
在集合视图中采用拖放是一个多步骤的过程。 我们将详细介绍在集合视图中集成拖放元素所需的每个细节。
UICollectionViewDragDelegate
要启用拖动 ,自定义对象必须符合UICollectionViewDragDelegate
协议。
它包含多种可以实现以定制集合视图的拖动行为的方法。
您需要采用此协议以支持拖动行为的唯一必需方法是:
我们将在后面的部分中详细研究方法。
另外,在viewDidLoad()
设置集合视图的dragDelegate
委托对象,以管理从中拖动项目。
collectionView.dragDelegate = self
UICollectionViewDropDelegate协议
要启用放置 ,自定义对象必须符合UICollectionViewDropDelegate
协议。
该协议唯一需要的方法是:
您可以根据需要实现其他方法,以自定义集合视图的放置行为。
另外,在viewDidLoad()
dropDelegate
自定义委托对象分配给集合视图的dropDelegate
属性。
collectionView.dropDelegate = self
启用拖动交互
要启用/禁用拖动,您可以自定义集合视图的dragInteractionEnabled
属性。
此属性的默认值在iPad上为true,在iPhone上为false。
因此,如果要在iPhone中提供拖放支持,请将其设置为true以启用从收藏夹视图中拖动内容的功能。
collectionView.dragInteractionEnabled = true
拖动单个项目
现在,我们已经配置了集合视图以支持拖放,现在可以实际编写实现它的代码了。
让我们从介绍一些支持拖放的重要类开始。 开始了:
- NSItemProvider —一个项目提供程序,用于在拖放期间在进程之间传送数据或文件。
- UIDragItem —从一个位置拖动到另一个位置的基础数据项的表示。
每个需要拖动的项目都必须表示为UIDragItem
的对象。
要允许从集合视图中拖动项目,请实现UICollectionViewDragDelegate
的唯一必需方法,并在指定的indexPath
返回该项目的一个或多个UIDragItem
对象。
我的天啊 ! was那是什么? 太不懂了.. !!!
不用担心 我们将在下面的代码中完成每个步骤:
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
让我们看看代码怎么说。
- 1号线-实现
collectionView(_:itemsForBeginning:at:)
的方法UICollectionViewDragDelegate
。 - 第3行-获取与所选择项目的
indexPath
相对应的数据。 使用您用作收集视图的数据源的模型。
在这里,我使用String
对象数组作为集合视图的数据源。 因此,item将对应于String
值。 - 第4行-创建的一个目的
NSItemProvider
使用item
在第3行中提取item
被铸造成NSString
因为NSItemProvider
接受一个对象和迅速String
是数值类型不是一个对象的类型。 - 第5行-从
itemProvider
创建一个UIDragItem
对象。 - 第6行
localObject
是与拖动项关联的自定义对象。 它仅适用于启动拖动活动的应用程序。
这是可选的,但可以更快地在同一应用程序中拖放内容。 - 第7行-返回
dragItem
数组 。
如果要忽略拖动,请返回一个空数组。
拖动多个项目
我们已经看到了如何从集合视图中拖动单个项目。 如果我想一次拖多个项目怎么办?
好了,我们有一个UICollectionViewDragDelegate
方法来实现。
此方法将指定的项目添加到现有的拖动会话中。
单击即可将项目添加到活动拖动会话中。 如果未实现此方法,则在集合视图中点击可以触发对项目或其他行为的选择。
它具有与collectionView(_:itemsForBeginning:at:)
类似的实现。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
您可以根据需要添加自己的约束。
示例 :如果您要删除的集合视图中已经存在该项目,则忽略添加。 在这种情况下,返回一个空数组。
放下提案— UICollectionViewDropProposal
我们选择了该项目,然后将其拖动。 现在,我们不能只是长时间拖拽该项目。 现在该怎么办? 放在哪里? 放下物品会怎样?
所有这些问题都指向一个非常具体的问题:
“您打算如何处理指定位置的下落?
您要复制项目还是将其移动到新位置?
还是要在某些特定条件下禁止运动?
不好了..!! 我可以取消吗?”
好吧好吧.. !!! 您的所有问题都有一个答案– 删除提案。 顾名思义,放置建议是当用户抬起手指时打算如何在特定位置处理放置的建议。
UIDropProposal —配置放置交互行为的配置,如果视图接受放置活动,则需要此配置。
每个提议都定义一个操作 - 枚举UIDropOperation ,该操作确定当用户放置拖动项时拖放活动的解析方式。 定义的操作可以是:
-
cancel
-不应传输任何数据,以取消拖动。 -
forbidden
-尽管在这种情况下移动或复制操作通常是合法的,但不允许放置操作。 -
copy
-由拖动项表示的数据应复制到目标视图。 -
move
—由拖动项表示的数据应移动,而不是复制。
UICollectionViewDropProposal — UIDropProposal的子类,专用于收集视图以处理放置建议。
集合视图建议还定义了一个可选的意图 — 枚举UICollectionViewDropIntent ,它确定如何将内容合并到集合视图中。 您可以在项目之间插入内容或将其添加到现有项目。 意图的可能值为:
-
unspecified
-unspecified
丢弃提议。 -
insertAtDestinationIndexPath
—将放置的项目插入指定的索引路径。 -
insertIntoDestinationIndexPath
—将放置的项目并入指定索引路径中的项目。
收集视图使用intent
信息向用户提供适当的视觉反馈 。
现在我们知道了什么是撤消提案,我们现在需要弄清楚的是如何以及在哪里实施该提案。
UICollectionViewDropDelegate
提供了一种方法,您可以在其中指定要使用的放置建议,即:
当用户拖动内容时,集合视图会反复调用此方法,以确定如果放置在指定位置发生,您将如何处理。
由于在用户将鼠标拖到集合视图上时会反复调用此方法,因此您的实现应尽快返回 。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
在上面的代码中,我使用了2个属性:
- localDragSession —如果拖动活动在其他应用程序中启动,则本地拖动会话为
nil
。 - hasActiveDrag —一个布尔值,指示是否从集合视图中提起了项目并且尚未将其删除。
因此,以上代码说明了这一点:
- 第16行-如果拖动活动在另一个应用程序中开始,则禁止放置。
- 第7行-否则,如果该项目是从与放置该项目相同的集合视图中提起的,则将其从源移动(重新排序)到目标索引路径。
- 第11行-否则,如果将其放置在另一个集合视图中,则将该项目复制到目标索引路径。
处理放置—复制
在明确了我们打算如何处理丢弃之后,让我们看一下实际丢弃后需要执行的实现细节。
要允许在集合视图中放置项目,请实现UICollectionViewDropDelegate
的唯一必需方法。
那是:
collectionView(_:performDropWith:)
—告诉您的委托将放置数据合并到集合视图中。
此方法为您提供了一个UICollectionViewDropCoordinator对象,可用于处理放置。 使用coordinator
,您可以获取以下项以更新集合视图的数据源:
-
items
—被拖动的项目 -
destinationIndexPath
—在集合视图中插入项目的索引路径。 它是一个可选值。 如果将项目插入空的收集视图或在收集视图的末尾,则返回nil
。 -
proposal
—有关如何合并已删除项目的当前提议
另外,合并项目时,请使用coordinator
对象的drop(_:to:)
或drop(_:toItemAt:)
方法来动画化从拖动项目的预览到集合视图中相应项目的过渡。
现在让我们看一些代码。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
上面的代码很简单:
- 从
coordinator
器获取destinationIndexPath
。 如果为nil
,则收集视图的最后一个索引路径用作放置该项目的目的地。 - 根据删除建议的
operation
采取适当的操作来更新收集视图move/copy/forbidden/cancel
。
如果您的放置建议是cancel/forbidden
,则不会调用collectionView(_:performDropWith:)
处理放置,因此您无需对其进行任何特殊处理。
如果建议的处理方式为move
,那么我们需要重新排序项目。 我们将在下一部分中讨论有关重新排序的更多信息。
在本节中,让我们看一下要copy
项目时如何处理掉落。
您可以使用集合视图的performBatchUpdates(_:completion:)
在集合视图中进行更改。
如果要在一个动画操作中而不是在多个单独的动画中对集合视图进行多次更改,则可以使用此方法。
批处理操作中的删除操作在插入之前进行。 这意味着在批处理操作之前,将相对于集合视图状态的索引处理删除的索引,而在批处理操作中所有删除之后,将相对于状态索引处理插入的索引。
这是您可以执行的操作:
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
要获取与拖动项目相对应的数据,可以使用以下选项之一:
- 如果设置了拖动项的
localObject
属性,则可以使用它。 如果内容源自您应用程序中的其他位置,它将可用。 - 另外,您可以使用拖动项目的
itemProvider
属性来获取数据。
处理放置—重新排序
移动 -当丢弃提案被指定为细胞的重新排序发生。
重新排序 -根据需要在同一/不同集合视图或表视图中将项目从源索引路径移动到目标索引路径。
我在这里明确地指的是表视图,因为表视图和集合视图的处理顺序有所不同。 我们将在这里讨论它们两个。
在表视图中 ,重新排序功能已经存在很长时间了。 好消息是我们可以继续使用😅。 无需执行任何特殊操作即可支持表视图中的重新排序。 您只需要:
- 在
tableView(_:dropSessionDidUpdate:withDestinationIndexPath:)
move
作为放置建议返回,以支持重新排序。 - 实现
UITableViewDataSource
tableView(_:canMoveRowAt:)
和tableView(_:moveRowAt:to:)
方法。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
如果实现了上述UITableViewDataSource
方法,则不会调用tableView(_:performDropWith:)
处理删除操作。
在集合视图中 ,重新排序的处理方式与复制相同。 唯一的区别是— 在复制时,您是在目标索引路径中插入一个全新项目,但是在重新排序时,您需要从源索引路径中删除一个项目,然后将其插入目标索引路径中。
逻辑改变了一点,其余一切保持不变。
注意:如果您尝试将项目重新排序到集合视图的末尾,则从collectionView(_:performDropWith:)
coordinator
获得的destinationIndexPath
可能是集合视图中的项目数。 在重新排序的情况下,集合视图中的项目数保持不变。 因此,您需要显式处理它,因为它可能会使Array index out of bounds
运行时错误。
等一下 ! 我有destinationIndexPath
,但是我从哪里得到sourceIndexPath
呢?
好吧,我们也有答案。
可以获得与使用coordinator
提取的每个项目相对应的sourceIndexPath
。 如果该项目源自同一集合视图,则此属性包含该项目的原始索引路径。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
在上面的代码中,单个项目被重新排序。 您可以根据需要对多个项目执行此操作。
重新排序速度— reorderingCadence
在重新排序的情况下,将项目拖到接受放置的集合视图上时,该集合视图会向用户提供适当的视觉反馈-更改/重新排列单元格以适应新的单元格。
我们可以控制的重新排序速度用更好的用户体验reorderingCadence类型的枚举UICollectionViewReorderingCadence对集合视图对象。
reorderingCadence
可以具有以下可能的值:
-
immediate
-immediate
物品重新排序到位。 ( 默认值 ) -
fast
-fast
重新排序商品,但延迟很短。 -
slow
—延迟后重新排序项目。
在viewDidLoad()
集合视图对象上设置reorderingCadence
的适当值。
collectionView.reorderingCadence = .fast
拖动预览— UIDragPreviewParameters
提起项目时,默认情况下,集合视图使用项目的可见范围来创建预览。 如果要自定义项目的外观,可以通过预览参数来实现。
UIDragPreviewParameters —一组用于调整拖动项目预览外观的参数。
参数指定预览的不同视觉方面,包括背景颜色和与预览关联的视图的可见区域。
如果您不想对拖动预览进行任何更改,请不要实现此方法,或者如果实现则返回nil
。
要自定义拖动预览,实施collectionView(_:dragPreviewParametersForItemAt:)
的方法UICollectionViewDropDelegate
。
![](https://i-blog.csdnimg.cn/blog_migrate/9e8d4f257d9e87e227c005d0ca2da84d.png)
而已。 这就是您需要在集合视图和表视图中进行拖放操作的全部。 继续..尝试一下!
样例项目
您可以从此处下载示例项目。
![](https://hackernoon.com/hn-images/1*ST2JF7fK3Ao5L82amVt0RA.gif)
促销活动
不要忘记阅读我的其他文章:
- Swift 4中有关Codable的一切
- 您一直想了解的有关iOS中通知的所有信息
- 使用GRADIENTS为它着色— iOS
- 您需要了解的有关iOS 10中的Today Extensions(Widget)的所有信息
- UICollectionViewCell选择变得简单.. !!
如有任何疑问,请随时发表评论。
From: https://hackernoon.com/drag-it-drop-it-in-collection-table-ios-11-6bd28795b313