在平移期间,各部分之间的UICollectionView单元格无法正确移动

时间:2016-08-04 19:40:48

标签: ios uicollectionview realm uicollectionviewlayout

要在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数据库中的中间单元位置更改未更新。或者我不正确?

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

1 个答案:

答案 0 :(得分:0)

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)
        }
    }
}