【问题标题】:UICollectionView cells are not moved correctly between sections during panningUICollectionView 单元格在平移期间未在部分之间正确移动
【发布时间】:2016-08-04 19:40:48
【问题描述】:

要在 UICollectionView 中移动项目,我使用 UILongPressGestureRecognizer。

我实现了以下手势处理程序:

func handleLongGesture(gesture: UILongPressGestureRecognizer) {
    switch(gesture.state) {
    case UIGestureRecognizerState.Began:
        guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else {break}
       collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
    case UIGestureRecognizerState.Changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
    case UIGestureRecognizerState.Ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

加上对集合视图委托方法moveItemAtIndexPath 的正确覆盖,在一个部分内移动单元格完美。此外,将单元格移动到其他可见部分也可以按预期工作。但是,将单元格移动到通过平移/向下滚动变得可见的部分时会出现问题,导致以下错误(我使用 Realm 数据库):

'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0.  The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (0), plus or minus the number of items inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'

问题似乎与updateInteractiveMovementTargetPosition 中的手势识别器跟踪位置变化有关,因为此方法出现错误。

我想updateInteractiveMovementTargetPosition 直接调用集合视图方法moveItemAtIndexPath(不是通过委托),这会导致错误,因为中间单元格位置更改不会在 Realm 数据库中更新。还是我说的不对?

有人知道为什么在部分之间移动适用于可见部分,而不是在平移期间吗?以及如何正确处理滚动/平移?

【问题讨论】:

    标签: ios uicollectionview realm uicollectionviewlayout


    【解决方案1】:

    UICollectionView 和 UITableView API 在 UI 状态中进行更新并要求将这些更新镜像到数据源中时非常无情。

    您需要更新 Realm 以反映 UI 状态,以保持 UICollectionView 满意。

    这是一个 Realm 支持的 UITableViewController 示例,其中包含可重新排序的单元格,您可以根据自己的 UICollectionView 用例进行调整:

    import UIKit
    import RealmSwift
    
    class ObjectList: Object {
        let list = List<DemoObject>()
    }
    
    class DemoObject: Object {
        dynamic var title = ""
    }
    
    class TableViewController: UITableViewController {
        var items: List<DemoObject>?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
            tableView.editing = true
    
            let realm = try! Realm()
            if realm.isEmpty {
                try! realm.write {
                    let list = ObjectList()
                    list.list.appendContentsOf(["one", "two", "three"].map {
                        DemoObject(value: [$0])
                    })
                    realm.add(list)
                }
            }
            items = realm.objects(ObjectList.self).first!.list
        }
    
        override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
            return items?.count ?? 0
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
            cell.textLabel?.text = items?[indexPath.row].title
            return cell
        }
    
        override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
            return .None
        }
    
        override func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
            return false
        }
    
        override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
            guard let items = items else { return }
            try! items.realm?.write {
                let itemToMove = items[fromIndexPath.row]
                items.removeAtIndex(fromIndexPath.row)
                items.insert(itemToMove, atIndex: toIndexPath.row)
            }
        }
    }
    

    【讨论】:

    • 这基本上是我为集合视图实现的,并且在单个部分的情况下可以正常工作(在表格视图中也适用于具有适当moveRowAtIndexPath 的多个部分)。我遇到的问题仅在我将移动单元格平移到多节集合视图中某个节的最后一个单元格之外时发生(单个节不会发生错误)。我发布了一些代码,可以在github 上重现此错误。这可能是 Swift 中的一个错误,还是我错误地更新了数据库?任何帮助将不胜感激
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多