【发布时间】:2021-10-13 05:24:52
【问题描述】:
我认为这可能是一个框架错误,我将其简化为一个极其简单和静态的示例(代码如下),具体情况如下:
- 允许将行重新排序到除最后一个位置之外的任何位置
- 如果用户试图将其放到最后一行,建议退回到原来的位置
这里是触发错误的方法:
- 取第一行之一并重新排序 - 一直拖到最后一行(不允许用户放下它),继续拖动它,但将其向上拖动并放在允许的位置位置,同时仍然可以查看最后一行。重要的是,要放置的行是屏幕外的行(原始位置在最终放置位置不可见)
- 最后一行将从视图中消失
-
最后一行没有调用
didEndDisplaying cell - 上下滚动会导致错误的视图状态,空视图会出现在“某处”
- 多滚动一下最终会再次解决问题
我不认为这是按预期工作的,但是通过更多测试,我怀疑从 proposedDestinationIndexPath 返回的 indexPaths 必须是单调的,例如如果拖动索引 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()
}
}
【问题讨论】:
-
这个使用 willDisplay 和 didEndDisplaying 是不是有问题?如果您删除这些并正确执行此操作会发生什么?
-
@matt 我不认为使用它们有什么问题。但是我将它们都删除了进行测试并直接在
cellForRowAt中设置了textLabel,但没有任何改变。
标签: ios swift uitableview uikit