完美解决 UITableViewCell 中加载 UIWebView 的高度计算问题

项目中遇到在 UITableViewCell 中加载 WKWebView 的需求,具体说就是要在一个 TableView 中显示若干个 WebView,每个WebView 的高度不尽相同。这个问题一直困扰了大半年,今天终于完美的解决了。

我的思路是:
1 获取数据,确定 tableView 的 cell 的数目和初始高度。
2 刷新 tableView,向每一个 cell 填充内容和初始高度,将初始高度赋值给 cell 的一个变量 cellHeight,并加载 webView。
3 等第 i 个 cell 中的 webView 加载完毕之后计算其高度 h。
4 令 h 与 cellHeight 进行比较。如果两个高度不等,通知 tableView 第 i 个 cell 的高度 h (即 cell 中 webView的实际高度),并调用如下代码刷新 cell:

tableView.reloadRows(at: [IndexPath (row: i, section: 0)], with: .none)

如果相等,OK,第 i 个 cell 显示正确。
5 重复 3

从得到数据开始说起,比如有16条数据需要显示:

    for _ in 0 ... 16 {
        let htmlString = "......"
        htmlStringArray.append(htmlString)
        cellHeightArray.append(60)
    }
    tableView.reloadData()

我在 TableView 中加载的数据放在数组 titleArray 里面,数组中每一项是需要显示的内容,一个 html 字符串。TableView 的每一个 cell 的高度我放在另一个数组 titleCellHeightArray 里面。那么 TableView 中第 i 个 cell 的高度即 titleCellHeightArray[i]。所以我们可以通过这两个数组确定 UITableView 的 cell 的数目、高度和内容:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return htmlStringArray.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return CGFloat(cellHeightArray[indexPath.row])
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! WKWebViewCell
        cell.delegate = self
        cell.tag = indexPath.row
        cell.setContent(htmlStringArray[indexPath.row], andHeight: cellHeightArray[indexPath.row])
        return cell
    }

UITableViewCell如下,布局中就一个 UIWebView,

    let HTML_HEAD = "test"
    let HTML_FOOT = ""
    let IMAGE = ""

    var delegate:WebViewCellHeightDelegate?
    
    let webView = WKWebView()
    var cellHeight = 0
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        initView()
    }
    
    func initView() {
        contentView.addSubview(webView)
        webView.navigationDelegate = self
        webView.isOpaque = false
        webView.scrollView.bounces = false
        webView.backgroundColor = UIColor.clear
        webView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview().inset(UIEdgeInsetsMake(10, 10, 10, 10))
        }
    }
    
    func setContent(_ content: String, andHeight height: Int) {
        cellHeight = height
        webView.loadHTMLString(HTML_HEAD + content + IMAGE + HTML_FOOT, baseURL: nil)
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.body.scrollHeight") { (result, error) in
            let h = (result as! Int) + 20
            //高度不同才通知,相同说明显示正确,不通知
            if (h != self.cellHeight) {
                self.delegate?.cell(height: h, withTag: self.tag)
            } 
        }
    }
    /// 将 cell 的高度通知给 tableView
    ///
    /// - Parameters:
    ///   - height: cell 的高度
    ///   - tag: cell 在 tableView 的位置
    protocol WebViewCellHeightDelegate:class {
        func cell(height: Int, withTag tag: Int)
    }

在 ViewController 中实现代理方法

    func cell(height: Int, withTag tag: Int) {
        cellHeightArray[tag] = height
        tableView.reloadRows(at: [IndexPath (row: tag, section: 0)], with: .none)
    }

至此,问题解决。效果如下
WechatIMG20.jpeg

你可能感兴趣的:(完美解决 UITableViewCell 中加载 UIWebView 的高度计算问题)