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

UITableView更新时阴影消失重现问题的解决方法咨询

问题描述

我使用tableView.beginUpdates()和tableView.endUpdates()实现带有阴影的单元格展开/收缩功能,但表格更新时所有单元格的阴影会先消失,之后再重新出现。我尝试过在willDisplayCell中设置阴影,也试过将阴影添加到独立视图、contentView以及cell本身,均无效。请问如何保持阴影不消失?

附带相关代码:

extension UIView {
    func addTutShadow(shadowOpacity: Float? = nil) {
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 0, height: 3)
        self.layer.shadowRadius = 12 * kHeightFactor
        self.layer.shadowOpacity = shadowOpacity ?? 0.12
    }
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TopicListCard
    cell.topic = rankedTopics[indexPath.section]
    cell.backgroundColor = .clear
    cell.backgroundView = UIView()
    cell.selectedBackgroundView = UIView()
    cell.delegate = self
    cell.addTutShadow()
    cell.setup()
    return cell
}

var selectedIndex = -1
    
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if selectedIndex != indexPath.section {
        selectedIndex = indexPath.section
        tableView.beginUpdates()
        tableView.endUpdates()
    } else {
        selectedIndex = -1
        tableView.deselectRow(at: indexPath, animated: true)
        tableView.beginUpdates()
        tableView.endUpdates()
    }
}
解决方案

1. 避免重复添加阴影

单元格复用过程中,每次调用addTutShadow会重复设置阴影属性,加上表格更新时的重绘逻辑,容易引发阴影闪烁。可以给自定义cell添加标记,确保阴影仅被添加一次:

class TopicListCard: UITableViewCell {
    private var hasAddedShadow = false
    
    override func layoutSubviews() {
        super.layoutSubviews()
        guard !hasAddedShadow else { return }
        addTutShadow()
        hasAddedShadow = true
    }
}

2. 启用图层光栅化优化

给添加阴影的视图开启光栅化,减少重绘时的阴影消失问题,同时保证清晰度:

extension UIView {
    func addTutShadow(shadowOpacity: Float? = nil) {
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 0, height: 3)
        self.layer.shadowRadius = 12 * kHeightFactor
        self.layer.shadowOpacity = shadowOpacity ?? 0.12
        // 开启光栅化并设置屏幕适配的缩放比例
        self.layer.shouldRasterize = true
        self.layer.rasterizationScale = UIScreen.main.scale
    }
}

3. 给内容容器视图添加阴影

不要直接给cell或contentView设置阴影,而是在contentView内部创建一个专门的容器视图,将cell的所有内容放入其中,再给这个容器添加阴影:

class TopicListCard: UITableViewCell {
    private let shadowContainer = UIView()
    
    func setup() {
        // 将容器视图添加到contentView并设置约束
        contentView.addSubview(shadowContainer)
        shadowContainer.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            shadowContainer.topAnchor.constraint(equalTo: contentView.topAnchor),
            shadowContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            shadowContainer.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            shadowContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
        
        // 将原cell的内容视图全部添加到shadowContainer中
        // ... 此处添加你的内容视图布局代码
        
        // 设置容器背景色并添加阴影
        shadowContainer.backgroundColor = .white
        shadowContainer.addTutShadow()
    }
}

4. 优化表格更新逻辑

确保tableView(_:heightForRowAt:)方法能准确返回单元格展开/收缩后的高度,避免动画过程中cell布局出现异常。同时移除cellForRowAt中重复设置背景的冗余代码,减少不必要的重绘触发。


内容的提问来源于stack exchange,提问作者Michael Montalbano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 14:54:19