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

如何让包含WKWebKit的UITableViewCell根据Web内容自动调整尺寸?

解决UITableViewCell中WKWebView自动适配高度的问题

这个问题的核心在于WKWebView加载内容是异步的,而UITableView计算Cell高度是同步的,所以布局时WebView还没渲染出内容,导致高度计算错误。直接修改frame的方式会破坏Auto Layout的约束系统,进而引发Cell重叠。下面是一套可靠的自动适配方案:

步骤1:配置TableView使用自动高度

在NewsListViewController的viewDidLoad中,替换固定高度设置,改用自动高度和预估高度:

override func viewDidLoad() {
    super.viewDidLoad()
    self.newsListTableView.delegate = self
    self.newsListTableView.dataSource = self
    self.newsListTableView.register(UINib(nibName: "NewsTableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
    
    // 启用自动高度
    newsListTableView.rowHeight = UITableView.automaticDimension
    // 设置预估高度,避免滚动时高度突变
    newsListTableView.estimatedRowHeight = 300.0
}

同时删除heightForRowAt方法,因为自动高度会替代它的作用。

步骤2:给Cell中的WKWebView添加高度约束

在NewsTableViewCell.xib中,给newsContentPreviewWebView添加一个高度约束,并创建IBOutlet连接到Cell类中,命名为webViewHeightConstraint(初始constant可以设为0或一个预估值)。

步骤3:修改Cell类,实现动态高度更新

更新NewsTableViewCell.swift,在WebView加载完成后获取内容高度,更新约束并通知TableView刷新:

import UIKit
import WebKit

@IBDesignable class NewsTableViewCell: UITableViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var dateTimeLabel: UILabel!
    @IBOutlet weak var newsContentViewContainer: UIView!
    @IBOutlet weak var newsContentPreviewWebView: WKWebView!
    // 添加WebView高度约束的IBOutlet
    @IBOutlet weak var webViewHeightConstraint: NSLayoutConstraint!
    
    @IBInspectable var titleText: String? {
        get { return self.titleLabel.text }
        set(value) { self.titleLabel.text = value }
    }
    
    @IBInspectable var dateTimeText: String? {
        get { return self.dateTimeLabel.text }
        set(value) { self.dateTimeLabel.text = value }
    }
    
    var contentHtml: String? {
        didSet {
            guard let html = contentHtml else { return }
            newsContentPreviewWebView.loadHTMLString(html, baseURL: nil)
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.newsContentPreviewWebView.navigationDelegate = self
        // 禁用WebView的滚动,避免内部滚动和Cell滚动冲突
        newsContentPreviewWebView.scrollView.isScrollEnabled = false
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        // 复用前重置高度约束,停止当前加载,避免旧内容干扰
        webViewHeightConstraint.constant = 0
        newsContentPreviewWebView.stopLoading()
        newsContentPreviewWebView.loadHTMLString("", baseURL: nil)
    }
}

extension NewsTableViewCell: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // 通过JS获取文档的实际高度
        webView.evaluateJavaScript("document.documentElement.scrollHeight") { [weak self] result, error in
            guard let self = self, let height = result as? CGFloat, error == nil else { return }
            
            // 更新WebView高度约束
            self.webViewHeightConstraint.constant = height
            // 强制Cell布局更新
            self.layoutIfNeeded()
            
            // 通知TableView重新计算当前Cell的高度
            if let tableView = self.superview as? UITableView {
                tableView.beginUpdates()
                tableView.endUpdates()
            }
        }
    }
}

这里把contentHtml改成了didSet属性,而非@IBInspectable的setter——@IBInspectable主要用于Interface Builder预览,代码中设置用didSet更可靠。

关键细节解释

  • 禁用WebView滚动:避免WebView内部滚动和TableView的滚动冲突,确保内容全部展开在Cell中。
  • prepareForReuse重置状态:解决Cell复用导致的旧内容残留、高度错误问题。
  • 用约束而非frame:Auto Layout会自动管理Cell的高度,通过更新约束constant,TableView能正确重新计算高度,不会出现重叠。
  • beginUpdates/endUpdates:触发TableView重新计算当前Cell的高度,确保高度更新后立即生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:31:22