首页 > 解决方案 > UITableView 重新排序删除的最后一行(框架错误或按预期工作?)

问题描述

我认为这可能是一个框架错误,我将其简化为一个非常简单和静态的示例(下面的代码),情况如下:

以下是触发错误的方法:

我不认为这是按预期工作的,但是通过更多测试,我怀疑从返回的 indexPathsproposedDestinationIndexPath必须是单调的,例如,如果拖动索引 4 并5,6...14在之前返回,则不能返回到sourceIndex (4),但是您必须锁定到允许的最高索引(本例中为 14)

我很好奇是否有人对此有详细信息或任何官方信息。什么是允许的,什么是不允许的?

class TestViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    private let tableView = UITableView()
    private var rows: [RowData] = [
        RowData("1"),
        RowData("2"),
        RowData("3"),
        RowData("4"),
        RowData("5"),
        RowData("6"),
        RowData("7"),
        RowData("8"),
        RowData("9"),
        RowData("10"),
        RowData("11"),
        RowData("12"),
        RowData("13"),
        RowData("14"),
        RowData("15")
    ]
    
    init() {
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.setNavigationBarHidden(false, animated: false)
        // ADVANCED VIEW
        tableView.backgroundColor = .systemBlue
        tableView.rowHeight = 120
        tableView.showsVerticalScrollIndicator = false
        tableView.showsHorizontalScrollIndicator = false
        tableView.separatorStyle = .none
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        //
        tableView.register(SpyCell.self, forCellReuseIdentifier: "default_row")
        tableView.delegate = self
        tableView.dataSource = self
        tableView.setEditing(true, animated: false)
//        tableView.allowsSelectionDuringEditing = false
//        tableView.allowsMultipleSelectionDuringEditing = false
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return rows.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withIdentifier: "default_row", for: indexPath)
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.textLabel?.text = rows[indexPath.row].title
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
    
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
//    func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
//        false
//    }
    
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .none
    }
    
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let removed = self.rows.remove(at: sourceIndexPath.row)
        self.rows.insert(removed, at: destinationIndexPath.row)
        // uncomment to confirm data is properly inserted
//        for row in self.rows {
//            print("row: \(row)")
//        }
    }
    
    func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
        if proposedDestinationIndexPath.row >= rows.count - 1 {
            return sourceIndexPath
            // BELOW WORKS as expected and doesn't cause the error
//            return IndexPath(row: rows.count - 2, section: 0)
        } else {
            return proposedDestinationIndexPath
        }
    }
    
    func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        print("didEndDisplaying cell : \(cell.textLabel?.text ?? "unexpected")")
    }
}

class RowData {
    let title: String
    
    init(_ title: String) {
        self.title = title
    }
}

class SpyCell: UITableViewCell {
    
    override func removeFromSuperview() {
        print("removeFromSuperview() \(textLabel?.text ?? "unexpected")")
        super.removeFromSuperview()
    }
}

标签: iosswiftuitableviewuikit

解决方案


我相信这个问题是由于试图移除并插入相同的位置。如果您将moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath函数更改为在源和目标相同时不移动行,则不会看到错误。

func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    if sourceIndexPath.row != destinationIndexPath.row {
        let removed = self.rows.remove(at: sourceIndexPath.row)
        self.rows.insert(removed, at: destinationIndexPath.row)
    }
}

编辑:这是一个包含此修复程序的视频,我没有看到您描述的错误: https ://imgur.com/a/EHPsXmj 。


推荐阅读