UIWebView 的全部内容嵌入到 UITableView

Posted

技术标签:

【中文标题】UIWebView 的全部内容嵌入到 UITableView【英文标题】:UIWebView's entire contents embedded in UITableView 【发布时间】:2016-01-10 03:25:26 【问题描述】:

我已经为此苦苦挣扎了两天,所以我向互联网上的聪明人致敬。

我正在展示一篇文章作为我的UITableView 的一部分。为了正确显示,我需要给代表一个单元格的高度,我希望它与UIWebView 的高度相同,所以我可以禁用 WebView 上的滚动并完整显示 Web 内容作为一个静态单元格。

我的第一种方法是在 heightForRowAtIndexpath 方法中渲染它,但这显然不起作用,因为我需要等待 UIWebViewDelegate 告诉我 web 视图何时完全加载并具有高度。过了一会儿,我找到了一个可行的解决方案,它使用 Web 视图代理在加载 Web 视图时刷新单元格高度。

在屏幕尺寸改变之前工作正常。来自旋转或全屏我的UISplitView。我在didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) 中强制对其进行了更新,但这会导致它在稳定到正确高度之前闪烁大约 10 次。我记录了这个更改,似乎 WebView 多次调用自身,导致循环。

正如this 日志中所见,从我旋转屏幕开始。

每次重新加载时它都会闪烁一次,如您所见,它会自行重新加载很多次。

所以。我需要一种在 uitableview 中显示整个 Web 视图内容的方法,并在屏幕尺寸发生变化时可靠地获取高度。如果有人以前以任何方式管理过这个,请告诉我。我会给任何能解决这个问题的人赏金和我的长子,因为这让我发疯。

这是我的相关代码。

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
    switch indexPath.row 
case 4:
        //Content
        print("Height for row called")
        return CGFloat(webViewHeight)


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    switch (indexPath.row)
//html Content View
    case 4:
        let cell = tableView.dequeueReusableCellWithIdentifier("ContentCell", forIndexPath: indexPath)
        var contentCell = cell as? ContentCell
        if contentCell == nil 
            contentCell = ContentCell()
        
        contentCell?.contentWebView.delegate = self
        contentCell?.contentWebView.scrollView.userInteractionEnabled = false
        contentCell?.contentWebView.loadHTMLString((post?.contentHTML)!, baseURL: nil)
        print("Cell For row at indexpath called")
        return contentCell!

func webViewDidFinishLoad(webView: UIWebView) 
    updateHeight()


func updateHeight()
    let webView = (self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 4, inSection: 0)) as! ContentCell).contentWebView
    if self.webViewHeight != Double(webView.scrollView.contentSize.height) 
        print("Previous WV Height = \(self.webViewHeight), New WV Height = \(webView.scrollView.contentSize.height)")
        self.webViewHeight = Double(webView.scrollView.contentSize.height)
        tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 4, inSection: 0)], withRowAnimation: .Automatic)
     else 
        return
    


override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) 
    print("rotated")
        self.updateHeight()
        //tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 4, inSection: 0)], withRowAnimation: .Automatic)

【问题讨论】:

我以前也遇到过这个问题,而且由于 UIWebViews 通常是一个神奇的黑匣子,所以我经常最终使用一种解决方法。假设您的文章主要是文本,请考虑通过 UITextView 以原生方式显示 HTML 内容,并将您的 HTML 作为属性字符串。有关在 UITextView 中显示 HTML 的基本示例,请查看以下答案:***.com/a/20996085/209855 @AaronAsh 我对此进行了研究,但除了不支持表格之外,对于我的用例来说,似乎带有 HTML 内容的属性标签解析太慢了。可悲... 将它放入 tableview 单元格应该不难,看看这里:***.com/a/18818036/209855 另外,我听说人们抱怨 HTML 解析速度慢,但在实践中从未见过。还值得试一试吗? 看起来应用程序正在对尺寸变化进行动画处理,并在动画期间多次调用 updateHeight()。在 updateHeight() 中放置一个断点以查看它是从哪里调用的。我猜你的代码中的另一个地方也有它。 旁注:从您的代码中,我了解到您的表格中只有一个带有嵌入式 tableView 的单元格?然后,我将在 VC 中处理整个 webview 逻辑(包括实例化),并在单元格出现在屏幕上时将 webview 添加为单元格的子视图(例如使用willDisplayCell)这将避免在单元格时重新加载所有内容离屏,等待 webview 显示。 【参考方案1】:

我通过在行更改动画中将 .Automatic 更改为 .None 解决了这个问题。它仍然是一个糟糕的解决方案,但至少它不再闪烁了。

【讨论】:

【参考方案2】:

我建议您独立于表格视图计算 Web 视图高度,并将维度存储为数据本身的一部分,并在 heightForRowAtIndexPath 调用中使用它返回。这是一种更容易的方式,因为您不必在表格视图显示期间处理计算表格高度。当未加载 html 内容时,使用标准高度和 web 视图的消息。

【讨论】:

【参考方案3】:

我认为您的实施没有问题。做几件事 您可以检查的东西很少

func webViewDidFinishLoad(webView: UIWebView) 
    updateHeight()
    //This function may get called multiple times depending on webpage. 


//Use
      self.tableView.beginUpdates()
      self.tableView.endUpdates()
//Instead of
 tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 4, inSection: 0)], withRowAnimation: .None)

    func updateHeight()
        let webView = (self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 4, inSection: 0)) as! ContentCell).contentWebView
        if self.webViewHeight != Double(webView.scrollView.contentSize.height)
        
            print("Previous WV Height = \(self.webViewHeight), New WV Height = \(webView.scrollView.contentSize.height)")
            self.webViewHeight = Double(webView.scrollView.contentSize.height)
            self.tableView.beginUpdates()
            self.tableView.endUpdates()
//            tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 4, inSection: 0)], withRowAnimation: .None)
         else 
            return
        
    

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation)

    print("rotated")
    let webView = (self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 4, inSection: 0)) as! ContentCell).contentWebView
    webView.reload();

您需要在方向更改时重新加载 webview。

【讨论】:

以上是关于UIWebView 的全部内容嵌入到 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

嵌入在 UIScrollview 中的 UIWebview 中的 Javascript 触摸事件

嵌入式 Facebook 帖子无法在 UIWebView 中正确显示

UIWebView 内容高度不正确

iOS 9 UIWebview 嵌入式视频全屏播放导致约束错误

flowcover 视图替代方案(使用 uiwebview 不使用 uiimage)

如何在 tvOS 上播放 YouTube 内容