ios - 尝试在重新排序已经在进行时开始对 Collection View 重新排序

标签 ios swift uicollectionview

我在两个 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'

我的设置如下,

  1. 我有两个 UICollectionView(例如 A 和 B)
  2. 在两个 Collection View 中都启用了重新排序
  3. 当你把一个item从A拖到B时,操作就是copy
  4. 当你将一个项目从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 []
}

重现步骤

  1. 有两个实现了上述委托(delegate)方法的 UICollectionViews
  2. 两者都应该跨越屏幕
  3. 从一个项目中拖出一个项目并尝试在另一个项目的顶部朝向屏幕边缘假装放下它
  4. 观察元素的重新排列,为新元素(要丢弃的元素)腾出空间
  5. 将手指从屏幕上滑开,观察拖动被取消后的效果。
  6. 观察为新项目腾出空间而重新排列的元素仍然保持不变。如果您有 Collection View 的布局委托(delegate)方法的控制台日志,您可能会发现它们不断被调用
  7. 现在,如果您尝试再次拖动某个项目或尝试离开屏幕,应用程序就会崩溃。

如果你们中的任何人对正在发生的事情有任何洞察力,那将有很大帮助。

最佳答案

在启动新拖动时结束放置位置 (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/

相关文章:

ios - UIStackView 自身的 intrinsicContentSize

ios - Swift 向下转型和协议(protocol)变量

ios - 如何设置导航栏

ios - 在 iOS7 中重新排序 UICollectionView

ios - 在 Swift 中使用标题中的分段控件更改 UICollectionView 的内容

ios - 如何在触摸单元格内的 slider 时取消 collectionView 手势?

ios - 我如何处理 UIAlertController 的操作?

ios - 如何将+作为NSString直接转换为加法运算符?

ios - 侧面菜单,以编程方式隐藏菜单选项

ios - 如何快速在键盘上添加文本字段?