UITableView 具有多个具有多行的部分。我需要部分独立运行
Posted
技术标签:
【中文标题】UITableView 具有多个具有多行的部分。我需要部分独立运行【英文标题】:UITableView with multiple Sections with multiple rows. I need sections to behave independently 【发布时间】:2019-10-11 06:19:01 【问题描述】:UITableView 有多个 Sections 和多行。所有行都添加了复选标记附件,我需要每个部分的行为不同。一个部分只允许选择 1 个复选标记,而另一个部分允许多选。所以目前我的第一部分只允许选择一行。 When another row in that section is selected it deselects the other.
在我的第二部分中,用户可以选择多个选项,这也是有效的,但是这是我的问题所在。当我在“第 2 节”中选择一行时,它会取消选择“第 1 节”中选择的选项。我正在使用一堆 switch 语句试图让它工作,但感觉必须有一个更简单的方法。有任何想法吗? (请在下面找到代码)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
let sectionNumber = indexPath.section
switch sectionNumber
case 0:
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
case 1:
if let cell = tableView.cellForRow(at: indexPath as IndexPath)
if cell.accessoryType == .checkmark
cell.accessoryType = .none
else
cell.accessoryType = .checkmark
case 2:
if let cell = tableView.cellForRow(at: indexPath as IndexPath)
if cell.accessoryType == .checkmark
cell.accessoryType = .none
else
cell.accessoryType = .checkmark
case 3:
if let cell = tableView.cellForRow(at: indexPath as IndexPath)
if cell.accessoryType == .checkmark
cell.accessoryType = .none
else
cell.accessoryType = .checkmark
default:
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
let sectionNumber = indexPath.section
let rowNumber = indexPath.row
switch sectionNumber
case 0:
tableView.cellForRow(at: indexPath)?.accessoryType = .none
case 1:break
case 2: break
case 3:break
default:break
【问题讨论】:
【参考方案1】:确保你有
tableView.allowsMultipleSelection = true
然后您可以取消选择第 0 部分中的选定行:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
if indexPath.section == 0
for selectedIndexPath in tableView.indexPathsForSelectedRows ?? [] where selectedIndexPath.section == 0
tableView.deselectRow(at: selectedIndexPath, animated: true)
tableView.cellForRow(at: selectedIndexPath)?.accessoryType = .none
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
tableView.cellForRow(at: indexPath)?.accessoryType = .none
【讨论】:
【参考方案2】:您的代码中最重要的问题是didSelectRowAt
中的更改不是持久的。当用户滚动时,您会得到意外的行为,因为单元格被重复使用。
例如,您必须在模型中添加一个属性以保持选择的状态
var isSelected = false
在控制器中声明一个属性来保存单个选择部分的选定索引路径
var selectedIndexPath : IndexPath?
在cellForRowAt
中根据isSelected
属性设置附件类型的状态
let item = sections[indexPath.section][indexPath.row]
cell.accessoryType = item.isSelected ? .checkmark : .none
在didSelectRowAt
的section 0中取消选择selectedIndexPath
处的行并选择当前行,你必须考虑取消选择当前行的情况。在其他部分切换isSelected
。更改模型然后重新加载调用cellForRowAt
并更新单元格的受影响行非常重要。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
switch indexPath.section
case 0:
if let selectedPath = selectedIndexPath
if selectedPath == indexPath // The current row is already selected: Deselected the row
sections[indexPath.section][indexPath.row].isSelected = false
selectedIndexPath = nil
tableView.reloadRows(at: [indexPath], with: .none)
else // Select the current row and deselect the row at `selectedIndexPath`
sections[selectedIndexPath.section][selectedIndexPath.row].isSelected = false
sections[indexPath.section][indexPath.row].isSelected = true
tableView.reloadRows(at: [indexPath, selectedIndexPath], with: .none)
selectedIndexPath = indexPath
else // nothing is selected: Select the row
sections[indexPath.section][indexPath.row].isSelected = true
selectedIndexPath = indexPath
tableView.reloadRows(at: [selectedIndexPath], with: .none)
default: // toggle the selection
sections[indexPath.section][indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .none)
【讨论】:
不需要,可以使用内置的UITableView.indexPathsForSelectedRows
。【参考方案3】:
在我的第二部分中,用户可以选择多个选项,这也是有效的,但是这是我的问题所在。当我在“第 2 节”中选择一行时,它会取消选择“第 1 节”中选择的选项。我正在使用一堆 switch 语句试图让它工作,但感觉必须有一个更简单的方法。有什么想法吗?
您似乎在这里犯的一个大错误是您依赖表格单元格来存储数据。表格中的给定行是否有复选标记应该是数据模型的一个特征,而不是表格单元格中的设置。您不会让用户检查某些行,因为它看起来不错 - 复选标记应该表示某种含义,并且应该在您的数据中捕获该含义。
我认为人们遇到这个问题的原因是他们在开始应用程序开发过程时考虑了应用程序的外观,因此他们从创建用户界面开始而没有考虑应该如何建模数据.他们将数据存储在通用结构中,例如数组或字典字典,以便他们可以快速运行某些东西,并且最终在他们的视图控制器中拥有大量代码,这些代码试图强制执行如果他们从以下方面考虑自然会出现的行为业务规则而不是用户界面操作。只需看看您使用的语言:您谈论的是可以在哪个部分选择多少行,而不是关于您的应用正在处理的数据的更自然规则。
要解决问题,你需要改变你的观点。暂时停止编写 UI 代码并专注于您的数据。您的目标是构建一个模型类来管理所有数据和管理该数据的规则——您正在 MVC 中创建 M。坐下来,为您的数据写出内容和规则。然后实现您的模型,并让该实现驱动表的行为。如果您只能在表格的第一部分选择一行,那应该是因为您的模型强制执行“每个客户都有一个销售联系人”之类的规则。表视图和视图控制器不应该知道或关心“只选择一个”的要求——它只是模型的一个特性。如果您在第一部分选择不同的行,这将导致在模型中选择不同的销售联系人,并且由于模型强制执行“仅一个”规则,模型将取消选择以前的销售联系人。这样做的好处是您可以更改模型中的业务规则——可能允许每位客户最多 三个 销售联系人——并且您无需对表格或视图控制器。
【讨论】:
以上是关于UITableView 具有多个具有多行的部分。我需要部分独立运行的主要内容,如果未能解决你的问题,请参考以下文章
UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接