Swift 4中TableView单元格与前一单元格数据对比及分组显示实现
解决Swift 4 TableView的两个常见问题:单元格数据对比与标题显示逻辑
嘿,这两个问题都是TableView开发中很典型的场景,我来给你一步步拆解解决方案:
问题1:如何对比当前单元格与前一单元格的数据?
核心思路是在tableView(_:cellForRowAt:)方法里,先拿到当前单元格对应的数据源,然后判断当前行不是第一行时,获取前一行的数据源,接着对比你需要的属性即可。
举个实际的代码例子,假设你的数据源是一个名为products的数组,每个元素是包含product_id的自定义模型:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath) as! ProductCell // 获取当前单元格对应的数据 let currentProduct = products[indexPath.row] // 只有当前不是第一行时,才对比前一行数据 if indexPath.row > 0 { let previousProduct = products[indexPath.row - 1] // 对比你需要的属性,比如product_id let isSameAsPrevious = currentProduct.product_id == previousProduct.product_id // 这里可以根据对比结果做后续逻辑,比如控制标题显示(对应问题2) } // 配置单元格的其他内容 cell.detailLabel.text = currentProduct.productDetail return cell }
问题2:根据product_id控制标题显示样式
基于上面的对比逻辑,我们可以进一步实现标题的显示规则:首行显示红色"Product 1",后续行如果和前一行product_id相同则隐藏标题,不同则显示对应编号的红色标题。
这里提供两种实现方式,按需选择:
方式1:动态统计(适合数据量较小的场景)
直接在cellForRowAt里动态计算当前是第几个不同的产品:
// 自定义Cell,包含用于显示标题的titleLabel class ProductCell: UITableViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var detailLabel: UILabel! } // 表格数据源方法 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath) as! ProductCell let currentProduct = products[indexPath.row] if indexPath.row == 0 { // 首单元格:显示红色"Product 1" cell.titleLabel.text = "Product 1" cell.titleLabel.textColor = .red cell.titleLabel.isHidden = false } else { let previousProduct = products[indexPath.row - 1] if currentProduct.product_id == previousProduct.product_id { // 和前一行product_id相同,隐藏标题 cell.titleLabel.isHidden = true } else { // 统计到当前行为止的唯一product_id数量,得到产品编号 let productNumber = countUniqueProductsUpToRow(indexPath.row) cell.titleLabel.text = "Product \(productNumber)" cell.titleLabel.textColor = .red cell.titleLabel.isHidden = false } } cell.detailLabel.text = currentProduct.productDetail return cell } // 辅助方法:统计到指定行为止的唯一product_id数量 private func countUniqueProductsUpToRow(_ row: Int) -> Int { var uniqueIDs = Set<String>() // 假设product_id是String类型,根据实际类型调整 for i in 0...row { uniqueIDs.insert(products[i].product_id) } return uniqueIDs.count }
方式2:提前分组(适合数据量较大的场景)
如果你的数据量比较大,动态统计会影响性能,建议提前对数据源按product_id分组,这样可以更高效地处理标题逻辑:
// 提前声明分组后的数据源 var groupedProducts: [[Product]] = [] override func viewDidLoad() { super.viewDidLoad() // 1. 先确保数据源按product_id排序(如果原本没排序的话) let sortedProducts = products.sorted { $0.product_id < $1.product_id } // 2. 按product_id分组 var currentGroup: [Product] = [] for product in sortedProducts { if let firstInGroup = currentGroup.first { if firstInGroup.product_id == product.product_id { currentGroup.append(product) } else { groupedProducts.append(currentGroup) currentGroup = [product] } } else { currentGroup.append(product) } } // 把最后一组加入 if !currentGroup.isEmpty { groupedProducts.append(currentGroup) } } // 表格数据源方法 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // 返回总行数:所有分组的行数之和 return groupedProducts.flatMap { $0 }.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath) as! ProductCell // 找到当前行所在的分组和组内位置 var groupIndex = 0 var rowInGroup = indexPath.row for (index, group) in groupedProducts.enumerated() { if rowInGroup < group.count { groupIndex = index break } else { rowInGroup -= group.count } } let currentProduct = groupedProducts[groupIndex][rowInGroup] // 只有组内第一行显示标题 if rowInGroup == 0 { cell.titleLabel.text = "Product \(groupIndex + 1)" cell.titleLabel.textColor = .red cell.titleLabel.isHidden = false } else { cell.titleLabel.isHidden = true } cell.detailLabel.text = currentProduct.productDetail return cell }
内容的提问来源于stack exchange,提问作者ken
相关产品推荐
相关产品推荐

