我为这个问题创建了一个简单的演示应用程序,这并不重要,但我正在寻找一个优雅的解决方案。我有一个包含多个部分的分组tableview,每个部分允许选择一个项目。这是代码:
class TableViewController: UITableViewController {
let sections = ["A", "B", "C", "D", "E", "F"]
let items = [
["one", "two", "three", "four"],
["one", "two", "three", "four"],
["one", "two", "three", "four"],
["one", "two", "three", "four"],
["one", "two", "three", "four"],
["one", "two", "three", "four"]
]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) // option 1
// let cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell") // option 2
cell.textLabel?.text = items[indexPath.section][indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell = tableView.cellForRowAtIndexPath(indexPath)
let section = indexPath.section
for rowNumber in 0..<tableView.numberOfRowsInSection(section) {
let tempPath = NSIndexPath(forRow: rowNumber, inSection: section)
let tempCell = tableView.cellForRowAtIndexPath(tempPath)
tempCell?.accessoryType = .None
}
cell?.accessoryType = .Checkmark
}
}
表格很长,表示滚动查看所有项目。现在,如果我选择选项1(dequeueReusableCellWithIdentifier
)并在第1部分中选择一行,则自动在第5部分被选中(可以通过滚动看到)。显然这不是故意的。如果我选择选项2,那么这不会发生,但是一旦滚动后它从视图中消失,该行就会被取消选择。也不是故意的。
到目前为止,我的解决方案是添加一个变量selectedCellIndices
,这是一个包含每个部分所选indexPath.row
的数组。这有效,但相当丑陋。
有关整洁解决方案的任何建议吗?
答案 0 :(得分:2)
问题:
当一行滚动屏幕并且新行变得明显可见时,滚动离开屏幕的行的单元格将重新用于刚刚可见的行。目前,您只在单元格上设置复选标记。需要记住的一点是, ROW是数据, CELL是该数据的视图。
如果您更新单元格上的checkMark,那么只更新视图。当行滚动屏幕时,该单元被回收或重复使用。
解决方案:
应用 MVC 技术。当您通过放置或删除复选标记来更新单元格时,您只需更新视图。接下来,您还需要更新模型。按模型我的意思是数据模型。
尝试创建数据类或数据模型:
import Foundation
class ChecklistItem {
var text = ""
var checked = false
func toggleChecked() {
checked = !checked
}
}
在你的控制器中创建一个数组,它将保存上述声明的类模型数据类型的数据,如下所示:
var items: [ChecklistItem]
在 didSelectRowAtIndex 功能中,您可以执行以下操作:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
// get the object from the array that was tapped by using the index path of the row
let item = items[indexPath.row]
// Toggle the checkMark, this method was declared within the data model as it was responsible for manipulating or updating the data.
item.toggleChecked()
if item.checked {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
以上是您的数据模型。现在,当您更新单元格时,还要通过声明该对象的checked变量true或false来更新数据模型。 True表示该行/单元格的复选标记,false表示没有复选标记。这样你就可以坚持你的复选标记。您还需要将这些对象保存到上面声明的items数组中。
如果您需要更多信息,请与我们联系。或者如果有些事情令人困惑。我希望这会有所帮助。
答案 1 :(得分:1)
选项1:
allowsMultipleSelection
上启用tableView
。tableView:didSelectRowAtIndexPath:
中,检查您是否已在该部分中选择了一个单元格(tableView.indexPathsForSelectedRows
上的一些过滤)。如果是这种情况,请取消选择。这将使用标准iOS选择样式(彩色背景),但您可以在自定义表格单元格setSelected:
中更改它(添加/删除附件),并配置表格单元格& #39; s selectionStyle
到None
。请记住在setSelected中调用super
,您仍需要设置内部selected
标记。
选项2:执行您的建议,将选择保留在单独的数组中,使用它在表格视图单元格出列时配置附件。
答案 2 :(得分:0)
显然,您应该将cell.accessoryType = .None
添加到cellForRowAtIndexPath
,因为可以重复使用单元格,而不会更改其最后的外观。