ios - UITableView 重新排序删除的最后一行(框架错误或按预期工作?)
问题描述
我认为这可能是一个框架错误,我将其简化为一个非常简单和静态的示例(下面的代码),情况如下:
- 允许将行重新排序到除最后一个位置之外的任何位置
- 如果用户试图将其放到最后一行,建议退回到原来的位置
以下是触发错误的方法:
- 取第一行之一并重新排序 - 一直拖到最后一行(不允许用户放下它),继续拖动它,但将其向上拖动并将其放在允许位置的某处,而仍然可以查看最后一行。重要的是,被删除的行是屏幕外的行(原始位置在最终放置位置不可见)
- 最后一行将从视图中消失
didEndDisplaying cell
不为最后一行调用- 向上和向下滚动将导致错误的视图状态,其中空视图将出现在“某处”
- 多滚动一点最终会再次解决问题
我不认为这是按预期工作的,但是通过更多测试,我怀疑从返回的 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()
}
}
解决方案
我相信这个问题是由于试图移除并插入相同的位置。如果您将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 。
推荐阅读
- mysql - 选择 GROUP BY 中的最新条目
- java - spring data - 使用 ElementCollection 查询左连接
- spring - Mapstruct:从注入的映射器调用函数
- flutter - Flutter:堆栈内的长文本重叠并从顶部开始
- java - 只计算字母字符
- java - 将布尔值(来自 mySQL 表)传递给 TableView 场景构建器
- c++ - 我对变量如何工作的理解是错误的吗?
- azure-data-factory - 如何将 Azure 数据工厂从一个帐户导出到另一个帐户
- node.js - 在 NodeJS / Express 中定义相同功能的 2 个可切换实现
- r - R中的mlr包,makeLearner mtry默认值