You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:05:21