无法将 CollectionViewCell 移动到末尾

Trouble moving CollectionViewCell to the end

我在 UIViewController 中有一个 UICollectionView。我配置了一个手势识别器来移动单元格。它适用于将单元格移动到除末尾以外的任何索引。最令人恼火的是,当我尝试将单元格移动到末尾时,应用程序不会崩溃——它只是挂起。我可以退出 ReorderViewController 并返回。视图正常重新加载。

我从viewDidLoad调用这个方法来配置手势识别器:

func configureGestureRecognizer() {
    // configure longPressGestureRecognizer
    longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(ReorderViewController.handleLongPressGesture))
    longPressGesture.minimumPressDuration = 0.5
    longPressGesture.delegate = self
    self.collectionView.addGestureRecognizer(longPressGesture)
}

UILongPressGestureRecognizer 被触发时,其处理程序被调用:

func handleLongPressGesture(gesture: UILongPressGestureRecognizer) {
    guard let selectedIndexPath = self.collectionView.indexPathForItem(at: gesture.location(in: self.collectionView)) else {
        return
    }
    let selectedCell = collectionView.cellForItem(at: selectedIndexPath)

    switch gesture.state {
    case .began:
        print("began")
        editMode = true
        collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
        selectedCell?.isSelected = true
    case .changed:
        editMode = true
        selectedCell?.isSelected = true
        print("changed")
        collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: self.collectionView))
    case .ended:
        print("ended")
        editMode = false
        selectedCell?.isSelected = false
        collectionView.endInteractiveMovement()
    default:
        print("default")
        editMode = false
        selectedCell?.isSelected = false
        collectionView.cancelInteractiveMovement()
    }
}

我可以毫无困难地使用手势移动单元格,只要我不将一个单元格移动到末尾即可。最烦人的是,应用程序不会崩溃——它只是挂起。我可以按 NavBar 上的 "Back" 按钮并转到之前的 ViewController 而不会崩溃,然后 return 到 ReorderViewController.

这是我移动单元格的代码:

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    let stuffToReorder = currentRoutine?.myOrderedSet.mutableCopy() as! NSMutableOrderedSet
    stuffToReorder.exchangeObject(at: sourceIndexPath.row, withObjectAt: destinationIndexPath.row)
    currentRoutine?.myOrderedSet = stuffToReorder as NSOrderedSet
    appDelegate.saveContext()
}

非常感谢任何关于我的错误的想法。

我想我已经破解了。我对 CoreData 问题的直觉是转移注意力(这也是我对它没有太多经验的原因!)。挂断是由处理程序方法开头的 guard 语句引起的。具体来说,您的方法检查是否存在与手势位置相关的有效索引路径;如果手势移出集合视图,我认为一切都会变得混乱,因此您会挂起(而不是崩溃),因为函数会在该点继续退出。然而,稍微移动一下似乎可以解决问题:

    func handleLongPressGesture(gesture: UILongPressGestureRecognizer) {
        guard let _ = collectionVC.collectionView else { return }

        switch gesture.state {
        case .began:
            guard let selectedIndexPath = collectionVC.collectionView!.indexPathForItem(at: gesture.location(in: collectionVC.collectionView)) else { return }
            selectedCell = collectionVC.collectionView!.cellForItem(at: selectedIndexPath)
            print("began")
            lastGoodLocation = gesture.location(in: collectionVC.collectionView!)
            collectionVC.collectionView!.beginInteractiveMovementForItem(at: selectedIndexPath)
        selectedCell.isSelected = true

        case .changed:

            selectedCell?.isSelected = true
            if collectionVC.collectionView!.frame.contains(gesture.location(in: view)) {
                print(gesture.location(in: view))
                print(collectionVC.collectionView!.frame)
                print("INSIDE COLLECTION VIEW!")
                collectionVC.collectionView!.updateInteractiveMovementTargetPosition(gesture.location(in: collectionVC.collectionView!))
                lastGoodLocation = gesture.location(in: collectionVC.collectionView!)
            }
            else
            {
                print("OUTSIDE COLLECTION VIEW!")
                collectionVC.collectionView!.updateInteractiveMovementTargetPosition(lastGoodLocation) // Not sure this is needed
            }
            print("changed")

        case .ended:
            print("ended")

            selectedCell?.isSelected = false
            collectionVC.collectionView!.endInteractiveMovement()

        default:
            print("default")

            selectedCell?.isSelected = false
            collectionVC.collectionView!.cancelInteractiveMovement()
        }
    }

以这种方式实现,我将 selectedCell 的 guard 语句移到了 switch 的 .began 案例中,因为这是它唯一被初始化的地方。因此,我必须将 selectedCell 声明为 class 属性 以便稍后在其他情况下可以引用它。我还引入了一个 CGPoint 变量 lastGoodLocation,它存储有效索引路径可用的最后一个位置 - 这样,如果手势在集合视图之外结束,单元格将发送到该索引路径。

无论如何,这有点粗糙,但肯定可以防止挂起。希望对您有所帮助!