我是Swift的新手。我在tableview中创建了一个简单的列表。当用户长按一行时,将检查该行。它工作得非常好。但是当我向下滚动时,勾选标记会改变它的位置。我还尝试在NSMutableSet中存储位置。但它仍然无法正常工作。也许我做错了什么。
这是我的代码:
长时间调用此方法。
func longpress(gestureRecognizer: UIGestureRecognizer)
{
let longpress = gestureRecognizer as! UILongPressGestureRecognizer
let state = longpress.state
let locationInview = longpress.location(in: tableview1)
var indexpath=tableview1.indexPathForRow(at: locationInview)
if(gestureRecognizer.state == UIGestureRecognizerState.began)
{
if(tableview1.cellForRow(at: indexpath!)?.accessoryType ==
UITableViewCellAccessoryType.checkmark)
{
tableview1.cellForRow(at: indexpath!)?.accessoryType =
UITableViewCellAccessoryType.none
}
else{
tableview1.cellForRow(at: indexpath!)?.accessoryType =
UITableViewCellAccessoryType.checkmark
}
}
}
答案 0 :(得分:1)
问题是细胞会被重复使用,当您更新复选标记时,您需要更新单元格,但不会更新模型。因此,当单元格滚出视图并重复使用单元格时,cellForRowAt
显然不会重置表格新行的复选标记。
同样,如果您将单元格滚动回视图,cellForRowAt
无法知道是否应该检查单元格。你必须
当您在单元格上检测到手势时,您必须更新模型才能知道此行的单元格应该有一个检查;以及
配置单元格时,cellForRowAt
必须查看此属性。
因此,首先要确保您的模型具有一些值,以指示是否已选中/选择它。在此示例中,我将使用" Item",但您使用更有意义的类型名称:
struct Item {
let name: String
var checked: Bool
}
然后您的视图控制器可以在cellForRowAt
:
class ViewController: UITableViewController {
var items: [Item]!
override func viewDidLoad() {
super.viewDidLoad()
addItems()
}
/// Create a lot of sample data so I have enough for a scrolling view
private func addItems() {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
items = (0 ..< 1000).map { Item(name: formatter.string(from: NSNumber(value: $0))!, checked: false) }
}
}
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell
cell.delegate = self
cell.textLabel?.text = items[indexPath.row].name
cell.accessoryType = items[indexPath.row].checked ? .checkmark : .none
return cell
}
}
现在,我通常让单元格处理诸如识别手势之类的内容并相应地通知视图控制器。因此,创建一个UITableViewCell
子类,并将其指定为故事板上单元格原型中的基类。但是该单元需要一些协议来通知视图控制器发生了长时间的压力:
protocol ItemCellDelegate: class {
func didLongPressCell(_ cell: UITableViewCell)
}
表视图控制器可以处理这个委托方法,切换其模型并相应地重新加载单元格:
extension ViewController: ItemCellDelegate {
func didLongPressCell(_ cell: UITableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
items[indexPath.row].checked = !items[indexPath.row].checked
tableView.reloadRows(at: [indexPath], with: .fade)
}
}
然后,UITableViewCell
子类只需要一个长按手势识别器,并在识别出手势后通知视图控制器:
class ItemCell: UITableViewCell {
weak var delegate: CellDelegate?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
addGestureRecognizer(longPress)
}
@IBAction func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
if gesture.state == .began {
delegate?.didLongPressCell(self)
}
}
}
顺便说一句,通过在单元格上设置手势,可以避免由于&#34;由于我长时间按下不属于单元格的内容而导致的混淆。单元格是手势识别器的正确位置。
答案 1 :(得分:0)
您没有在任何地方存储更改。
为避免使用太多内存,手机会重复使用单元格,并要求您在TableView
的{{1}}中配置它们。
假设你有一个名为dataSource
的数组,它有一些结构可以存储你想要显示为单元格的内容。您需要更新此数组并告诉tableView重新加载您的单元格。
data
在配置单元格时始终设置附件:
func userDidLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
// We only care if the user began the longPress
guard gestureRecognizer.state == UIGestureRecognizerState.began else {
return
}
let locationInView = gestureRecognizer.location(in: tableView)
// Nothing to do here if user didn't longPress on a cell
guard let indexPath = tableView.indexPathForRow(at: locationInView) else {
return
}
// Flip the associated value and reload the row
data[indexPath.row].isChecked = !data[indexPath.row].isChecked
tableView.reloadRows(at: [indexPath], with: .automatic)
}