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

iOS技术问题:在UIKit的UITableView中复用SwiftUI视图时出现UI变形

UITableViewCell复用SwiftUI视图时出现UI变形的解决方案

嘿,我一眼就看出问题出在哪了——你踩了UITableView复用机制和重复添加视图的坑!

每次给title赋值的时候,你都会新建一个UIHostingController,然后把它的view直接加到cell的contentView里。但UITableView的cell是会被复用的啊!当cell滑出屏幕再滑回来时,旧的hostingView根本没被移除,新的又叠加上去,多个SwiftUI视图挤在一起,可不就变形了嘛。

给你两种靠谱的解决方案,按需选:

方案一:复用前清理旧的HostingView

这个方法简单直接,每次更新内容前先把之前的hostingView删掉,再添加新的。我们给cell加个属性存当前的hostingView,方便管理:

class TestCell: UITableViewCell {
    // 保存当前的hostingView引用,方便后续移除
    private var currentHostingView: UIView?
    
    var title: String? {
        didSet {
            // 先把旧的视图删掉,避免叠加
            currentHostingView?.removeFromSuperview()
            
            guard let title = title else { return }
            
            let hostingController = UIHostingController(rootView: TestView(text: title))
            let hostingView = hostingController.view!
            hostingView.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(hostingView)
            
            // 更新当前视图的引用
            currentHostingView = hostingView
            
            // 约束要绑到contentView上,别绑cell本身!
            NSLayoutConstraint.activate([
                hostingView.topAnchor.constraint(equalTo: contentView.topAnchor),
                hostingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
                hostingView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
                hostingView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
            ])
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 加个保险:cell准备复用的时候彻底重置状态
    override func prepareForReuse() {
        super.prepareForReuse()
        currentHostingView?.removeFromSuperview()
        currentHostingView = nil
        title = nil
    }
}

方案二:只创建一次HostingView,通过Binding更新内容

如果你的SwiftUI视图比较复杂,频繁创建销毁会有性能损耗,那可以用这种方法——只初始化一次hostingView,通过绑定值来更新内容:

首先修改你的SwiftUI视图,用@Binding接收文本:

struct TestView: View {
    @Binding var text: String
    
    var body: some View {
        Text(text)
        // 这里放你原来的SwiftUI布局
    }
}

然后修改TestCell:

class TestCell: UITableViewCell {
    private var textBinding = Binding<String>(get: { "" }, set: { _ in })
    private let hostingController: UIHostingController<TestView>
    
    var title: String? {
        didSet {
            textBinding.wrappedValue = title ?? ""
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        // 初始化绑定和hostingController
        var currentText = ""
        textBinding = Binding<String>(
            get: { currentText },
            set: { currentText = $0 }
        )
        hostingController = UIHostingController(rootView: TestView(text: textBinding))
        
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        let hostingView = hostingController.view!
        hostingView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(hostingView)
        
        NSLayoutConstraint.activate([
            hostingView.topAnchor.constraint(equalTo: contentView.topAnchor),
            hostingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            hostingView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            hostingView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        textBinding.wrappedValue = ""
    }
}

小提醒

  • 约束一定要绑到contentView上,而不是cell本身,这是UITableViewCell布局的最佳实践,能避免很多奇怪的布局问题。
  • prepareForReuse方法一定要实现,复用前重置状态,彻底避免旧数据残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:02:43