重新排序后,细胞位于另一个细胞后面

时间:2016-05-27 13:53:33

标签: ios swift uitableview

我正在尝试创建重新订购指标。所以我试图做的是当用户拖动单元格时。在用户想要放置单元格的地方,其他单元格添加了背景。我已经做到了。但是当用户丢弃单元格时,需要删除指示符单元格,并且表格必须保持与用户期望的相同。

现在我有以下问题。当用户放下单元格时。指示器单元被正确移除,但掉落的单元突然位于另一个单元后面。

屏幕截图澄清:

Begin state End state View hierarchy in xcode in endstate

我的代码:

import UIKit
import PureLayout

class ViewController: UIViewController {

    lazy var tableView: UITableView = {
        let tableView = UITableView(forAutoLayout: ())
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .SingleLine
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Default")
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Indicator")
        tableView.tableFooterView = UIView()

        return tableView
    }()

    private var data: [Int] = [Int]()

    private var isIndicatorRowAddedInSection: Bool = false
    private var lastIndicatorRowIndexPath: NSIndexPath?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(self.tableView)

        self.tableView.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsetsZero, excludingEdge: .Top)
        self.tableView.autoPinEdgeToSuperviewEdge(.Top, withInset: 40)

        for index in 0..<20 {
            data.append(index)
        }

        self.tableView.editing = true
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

extension ViewController: UITableViewDelegate {


    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 44
    }

    func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {

    }

    func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {

        if let lastIndexPath = self.lastIndicatorRowIndexPath {
            print("Need to delete a row on section \(lastIndexPath.section) row \(lastIndexPath.row)")
            self.isIndicatorRowAddedInSection = false
            self.lastIndicatorRowIndexPath = nil
            tableView.beginUpdates()
            tableView.deleteRowsAtIndexPaths([lastIndexPath], withRowAnimation: .Fade)
            tableView.endUpdates()
        }

        let itemToMove = self.data[fromIndexPath.row]
        self.data.removeAtIndex(fromIndexPath.row)
        self.data.insert(itemToMove, atIndex: toIndexPath.row)
    }

    func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
        return .None
    }

    func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return false
    }

    func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath,
                   toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath {

        if let lastIndexPath = self.lastIndicatorRowIndexPath {
            print("Target indexpath indexpath to delete row \(lastIndexPath.section) row \(lastIndexPath.row)")
            self.isIndicatorRowAddedInSection = false
            tableView.beginUpdates()
            tableView.deleteRowsAtIndexPaths([lastIndexPath], withRowAnimation: .Fade)
            tableView.endUpdates()

            self.lastIndicatorRowIndexPath = nil
        }

        self.isIndicatorRowAddedInSection = true

        self.lastIndicatorRowIndexPath = proposedDestinationIndexPath

        tableView.beginUpdates()
        print("Indicator view inserted at section \(proposedDestinationIndexPath.section) row \(proposedDestinationIndexPath.row)")
        tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: proposedDestinationIndexPath.row, inSection: proposedDestinationIndexPath.section)], withRowAnimation: .Automatic)
        tableView.endUpdates()

        return proposedDestinationIndexPath
    }

}

extension ViewController: UITableViewDataSource {

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if self.isIndicatorRowAddedInSection {
            return self.data.count + 1
        }
        return self.data.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if let indicatorIndexPath = self.lastIndicatorRowIndexPath where isIndicatorRowAddedInSection {
            if indicatorIndexPath.section == indexPath.section && indicatorIndexPath.row == indexPath.row {
                let cell = tableView.dequeueReusableCellWithIdentifier("Indicator", forIndexPath: indexPath)

                return cell
            }
        }

        let cell = tableView.dequeueReusableCellWithIdentifier("Default", forIndexPath: indexPath)

        cell.textLabel?.text = String(self.data[indexPath.row])
        return cell

    }
}

我没有看到问题所在。有人能帮助我吗?

1 个答案:

答案 0 :(得分:0)

我发现了问题。在moveRow中,它在线程1(主线程)上执行,但似乎不是。因为当你使用异步调度将它包装到主线程时,它才能正常工作。

完整的工作代码:

import UIKit
import PureLayout

class ViewController: UIViewController {

    lazy var tableView: UITableView = {
        let tableView = UITableView(forAutoLayout: ())
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .SingleLine
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Default")
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Indicator")
        tableView.tableFooterView = UIView()

        return tableView
    }()

    private var data: [Int] = [Int]()

    private var isIndicatorRowAddedInSection: Bool = false
    private var lastIndicatorRowIndexPath: NSIndexPath?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(self.tableView)

        self.tableView.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsetsZero, excludingEdge: .Top)
        self.tableView.autoPinEdgeToSuperviewEdge(.Top, withInset: 40)

        for index in 0..<5 {
            data.append(index)
        }

        self.tableView.editing = true
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

extension ViewController: UITableViewDelegate {


    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 44
    }

    func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {

    }

    func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {


        let itemToMove = self.data[fromIndexPath.row]
        self.data.removeAtIndex(fromIndexPath.row)
        self.data.insert(itemToMove, atIndex: toIndexPath.row - 1)

        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            if let lastIndexPath = self.lastIndicatorRowIndexPath {
                print("Need to delete a row on section \(lastIndexPath.section) row \(lastIndexPath.row)")
                self.isIndicatorRowAddedInSection = false
                self.lastIndicatorRowIndexPath = nil
                tableView.beginUpdates()

                // Need to put some logic if you pull to top it has to be + 1
                tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: lastIndexPath.row - 1, inSection: 0)], withRowAnimation: .Fade)
                tableView.endUpdates()
            }
        })
    }

    func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
        return .None
    }

    func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return false
    }

    func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath,
                   toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath {

        if let lastIndexPath = self.lastIndicatorRowIndexPath {
            print("Target indexpath indexpath to delete row \(lastIndexPath.section) row \(lastIndexPath.row)")
            self.isIndicatorRowAddedInSection = false
            tableView.beginUpdates()
            tableView.deleteRowsAtIndexPaths([lastIndexPath], withRowAnimation: .None)
            tableView.endUpdates()

            self.lastIndicatorRowIndexPath = nil
        }

        self.isIndicatorRowAddedInSection = true

        self.lastIndicatorRowIndexPath = proposedDestinationIndexPath

        tableView.beginUpdates()
        print("Indicator view inserted at section \(proposedDestinationIndexPath.section) row \(proposedDestinationIndexPath.row)")
        tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: proposedDestinationIndexPath.row, inSection: proposedDestinationIndexPath.section)], withRowAnimation: .Automatic)
        tableView.endUpdates()

        return proposedDestinationIndexPath
    }

}

extension ViewController: UITableViewDataSource {

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if self.isIndicatorRowAddedInSection {
            return self.data.count + 1
        }
        return self.data.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        if let indicatorIndexPath = self.lastIndicatorRowIndexPath where isIndicatorRowAddedInSection {
            if indicatorIndexPath.section == indexPath.section && indicatorIndexPath.row == indexPath.row {
                let cell = tableView.dequeueReusableCellWithIdentifier("Indicator", forIndexPath: indexPath)
                cell.textLabel?.text = "IndicatorView: ROW \(indexPath.row) SECTION = \(indexPath.section)"
                print("Indictorview cell for row")
                return cell
            }
        }

        let cell = tableView.dequeueReusableCellWithIdentifier("Default", forIndexPath: indexPath)

        cell.textLabel?.text = "ROW = \(indexPath.row) SECTION = \(indexPath.section)"
        return cell

    }
}