我在两个 UICollectionView 之间实现了拖放。有时我会遇到这个奇怪的错误。
Assertion failure in -[UICollectionView _beginInteractiveMovementForItemAtIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.54.4/UICollectionView.m:8459
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to begin reordering on collection view while reordering is already in progress'
我的设置如下,
- 我有两个 UICollectionView(例如 A 和 B)
- 在两个 Collection View 中都启用了重新排序
- 当你把一个item从A拖到B时,操作就是copy
- 当你将一个项目从B拖到A时。操作是从B中删除。A不受影响。
到目前为止我的代码如下(抽象版)
// Drop delegate
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
print(#function)
let destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
self.performDrop(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
} else if collectionView.tag == CollectionView.timeline.rawValue {
// Get last index path of collection view.
let section = collectionView.numberOfSections - 1
let row = collectionView.numberOfItems(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
self.performDrop(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
print(#function)
if session.localDragSession != nil {
// Trying to drag and drop an item within the app
if collectionView.hasActiveDrag {
// Trying to re-oder within the same collection view
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
} else {
// Trying to copy an item from another collection view
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
}
} else {
// Trying to drag and drop an item from a different app
return UICollectionViewDropProposal(operation: .forbidden)
}
}
// Drag delegate
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
print(#function)
var item: Item?
if collectionView.tag == CollectionView.media.rawValue {
item = mediaItems[indexPath.row]
} else {
item = StoryManager.sharedInstance.timelineItems[indexPath.row]
}
if let item = item {
let itemProvider = NSItemProvider(object: item.id as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
return []
}
重现步骤
- 有两个实现了上述委托(delegate)方法的 UICollectionViews
- 两者都应该跨越屏幕
- 从一个项目中拖出一个项目并尝试在另一个项目的顶部朝向屏幕边缘假装放下它
- 观察元素的重新排列,为新元素(要丢弃的元素)腾出空间
- 将手指从屏幕上滑开,观察拖动被取消后的效果。
- 观察为新项目腾出空间而重新排列的元素仍然保持不变。如果您有 Collection View 的布局委托(delegate)方法的控制台日志,您可能会发现它们不断被调用
- 现在,如果您尝试再次拖动某个项目或尝试离开屏幕,应用程序就会崩溃。
如果你们中的任何人对正在发生的事情有任何洞察力,那将有很大帮助。
最佳答案
在启动新拖动时结束放置位置 (UICollectionView) 中的任何交互式移动解决了我的问题。我必须按如下方式修改我的 UICollectionViewDragDelegate 方法,
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
var item: Item?
if collectionView.tag == CollectionView.media.rawValue {
item = mediaItems[indexPath.row]
// New line to fix the problem. 'timeline' is the IBOutlet of the UICollectionView I'm going to drop the item
timeline.endInteractiveMovement()
} else {
item = StoryManager.sharedInstance.timelineItems[indexPath.row]
// New line to fix the problem. 'media' is the IBOutlet of the UICollectionView I'm going to drop the item
media.endInteractiveMovement()
}
if let item = item {
let itemProvider = NSItemProvider(object: item.id as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
return []
}
为了解决应用程序在导航时崩溃的问题,我必须结束 viewWillDisappear 中的任何交互式移动。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 'media' and 'timeline' are the IBOutlets of the UICollectionViews I have implemented drag and drop
timeline.endInteractiveMovement()
media.endInteractiveMovement()
}
希望 Apple 能在未来的版本中解决这个问题。
关于ios - 尝试在重新排序已经在进行时开始对 Collection View 重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52488822/