ios - 如何使用底层 WKWebKit 自动调整 UITableViewCell 的大小,使其尊重 Web View 的内容?

标签 ios swift xcode xib

在我的 iOS 应用程序中,我想显示几个包含一些 HTML 的项目。为此,我构建了一个包含 UITableViewNewsListViewController。对于那个 UITableView(导出:newsListTableView),我创建了一个名为 NewsTableViewCell 的自定义 UITableViewCell,它将通过代表们。 NewsTableViewCell 包含一个将显示我的 HTML 的 WKWebKit 控件。这是我的代码:

NewsListViewController.swift

import UIKit

class NewsListViewController: UIViewController {

    @IBOutlet weak var newsListTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.newsListTableView.delegate = self
        self.newsListTableView.dataSource = self
        self.newsListTableView.register(UINib(nibName: "NewsTableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
    }

}

extension NewsListViewController: UITableViewDelegate {

}

extension NewsListViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
    {
        return 300.0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! NewsTableViewCell
        cell.titleText = "My Title"
        cell.dateTimeText = "01.01.1998"
        cell.contentHtml = "<html><head><meta name=\"viewport\" content=\"initial-scale=1.0\" /><style>html, body { margin: 0; padding: 0; font-size: 15px; }</style></head><body><b>Hello News</b><br />Hello News<br />Hello News<br />Hello News</body></html>"
        return cell
    }

}

NewsTableViewCell.xib

NewsTableViewCell.xib preview

我的 WKWebKit(导出:newsContentPreviewWebView)位于 UIView(导出:newsContentViewContainer)内与 UIView 一起成长的适当约束。我的 UIView 也带有适当的约束,可以随着整个单元格的增长而增长。

NewsTableViewCell.swift

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!

    @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
        }
    }

    @IBInspectable var contentHtml: String? {
        get {
            return nil
        }
        set(value) {
            self.newsContentPreviewWebView.loadHTMLString(value ?? "", baseURL: nil)
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.newsContentPreviewWebView.navigationDelegate = self
    }

}

extension NewsTableViewCell: WKNavigationDelegate {
}

这是结果:

App preview without auto sizing

现在,我希望单元格尽可能小,但仍显示完整的 WKWebKit 内容。

当我删除...

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
    return 300.0
}

...从 NewsListViewController.swift 单元格高度将只考虑 WKWebKit 控件上方的标签:

App preview showing failed auto sizing of the cell

我认为这是发生了,因为当应用调整单元格大小时我的 WKWebKit 的内容没有加载。

我试图通过听取 WKWebKit 的 >> 完成导航 << 在我的 NewsTableViewCell.swift 中调用委托(delegate)并调整父 View 的大小来解决这个问题,像这样的整个单元格高度:

extension NewsTableViewCell: WKNavigationDelegate {        
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
            if complete != nil {
                webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
                    let h: CGFloat = height as! CGFloat

                    let newsContentFrame: CGRect = self.newsContentViewContainer.frame
                    self.newsContentViewContainer.frame = CGRect(x: newsContentFrame.minX, y: newsContentFrame.minY, width: newsContentFrame.width, height: h)

                    let tableCellFrame: CGRect = self.frame
                    self.frame = CGRect(x: tableCellFrame.minX, y: tableCellFrame.minY, width: tableCellFrame.width, height: tableCellFrame.height + h)
                })
            }
        })
    }
}

这是结果:

App preview showing overlapping of cells when trying to set the size, manually

单元格重叠,这表明我试图以错误的方式解决这个问题。

自动调整自定义表格单元格大小以适应其所有内容(包括 WKWebKit 的内容)的正确方法是什么?

最佳答案

问题是你永远不会给你的单元格一个高度。手动设置框架

self.frame = CGRect(x: tableCellFrame.minX, y: tableCellFrame.minY, width: tableCellFrame.width, height: tableCellFrame.height + h)

不好。您应该始终使用专用委托(delegate)方法或估计行高技术 ( Using Auto Layout in UITableView for dynamic cell layouts & variable row heights )。

问题很棘手:您需要等待 webview 加载才能计算其高度。但是在加载 webview 的内容之前调用 heightForCell 时需要它的高度。

我看到 5 种解决方案:

  • 您将 tableview 转换为包含所有新闻的巨大 webview。然后您将元数据手动注入(inject)到 html 中
  • 您解析 html 并提取所需的信息。这只有在所有新闻 html 具有相同结构时才有可能。这也很难 ( RegEx match open tags except XHTML self-contained tags )。
  • 你照原样进行。但是当 completionHandler 被调用时,您调用一个委托(delegate)(例如您的 View Controller ),它将重新加载相应的单元格并为其提供刚刚计算的正确高度。这个解决方案很简单,但在每次加载之前,你需要在你的单元格中给出一个错误的高度。因此,您可以在单元格中定义一个加载状态,但是当单元格即将出现时,您总会遇到一些小故障。
  • 在显示表格 View 之前,加载所有单元格的内容并在后台线程上计算它们相应的高度。您可以为每个单元格使用 Operation,等待单元格的 html 加载和评估给定的 javascript。完成所有操作后,重新加载 tableview
  • 更改您的设计:仅显示新闻列表并在选择单元格时将新闻内容加载到单独的 View Controller 中

关于ios - 如何使用底层 WKWebKit 自动调整 UITableViewCell 的大小,使其尊重 Web View 的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48463531/

相关文章:

ios - 如何在容器 View 中显示 WKWebView 内容

ios - AFNetworking 问题 : NSErrorFailingURLKey=url, NSLocalizedDescription=请求失败:错误请求 (400)

ios - 如何正确地将弱引用传递给函数的调用者?

objective-c - NSTabViewItem 按钮标签可以调整大小吗?

iphone - 如何阻止willTerminate方法的调用?

ios - 位置管理器 :didChangeAuthorization vs locationManagerDidChangeAuthorization

swift - 我已将设备的当前时间格式设置为 24 小时制,现在我需要使用 "am"、 "pm"从 24 小时制计算 12 小时制时间

iOS AVFoundation : Get AVCaptureDevice. 格式的视频尺寸

xcode - WebView 完成启动 Mac OSX

ios - git push 说一切都是最新的