13

I have to integrate WKWebView inside UITableView (please don't question that).

I made sure the WKWebView scroll is disabled, this way I avoid having a scrollable view within a scrollable view (UITableView).

However, when the HTML content inside the WKWebview is large, let's say twice the screen, I find that the content below the screen is not shown to the user, i.e. when the user scrolls the table view there is only white\empty screen where the WKWebView is...

I update the height of the WebViewTableViewCell according to:

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    let height = webView.scrollView.contentSize.height
    ...
    ...
    delegate.updateWebViewCellHeight(height: self.cellHeight)
}

I guess it's probably the effect of some optimization on WKWebView which allow it to render DOM's only when they are shown on screen.

My question is, what can I do in order to make sure all the content inside the WKWebView is shown to the user when she scrolls the table view?

P.S. UIWebView renders all the content just fine, it seems to be happening only in WKWebView

See image below:

enter image description here

Oded Regev
  • 4,065
  • 2
  • 38
  • 50
  • How and when are you setting the web view frame / cell size? If you stop at the view debugger are the views all the right size? – Wain Dec 04 '16 at 19:19
  • See my edits about how I resize the webview cell – Oded Regev Dec 05 '16 at 07:39
  • `webView.scrollView.contentSize` may not be accurate at the time the notification is posted. I suggest adding an observer on the `webView.scrollView.contentSize` keyPath and then updating your cell size from there. – Léo Natan Dec 05 '16 at 15:24
  • There is no problem with the notification timing... I catch it in webview finishLoad() method and it works fine. As I mentioned the same code for UIWebView works perfectly – Oded Regev Dec 05 '16 at 15:44

3 Answers3

15

You can call setNeedsLayout on the WKWebView, (Swift):

Note this is the scrollView for the UITableView.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    // use IndexPath for row/section with your WKWebView
    if let cell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? WKWebViewCell { // Here we take our cell
        cell.wkWebView?.setNeedsLayout()
    }
}

See WKWebView not rendering correctly in iOS 10

Community
  • 1
  • 1
ODB
  • 366
  • 1
  • 5
2

This is really Apple optimization - to render only visible part of web-view. There are several similar questions about this issue:

WKWebView screenshot not completely rendering full page height

How to capture a full page screenshot of WKWebview?

Try to call [self.webView setNeedsDisplay] in table view delegate's scrollViewDidScroll: method.

Community
  • 1
  • 1
k06a
  • 17,755
  • 10
  • 70
  • 110
1

Make sure when updating cell height,TableViewCell is not reloading WebView. Otherwise you'll stuck in endless loop and weird behavior and height will reset again and again.

var CGFloat : webViewHeight = 0.0 

//Track the current height of webView.

// MARK: - WKWebView Delegate
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    weak var weakSelf = self
    webView.evaluateJavaScript("document.documentElement.style.webkitUserSelect='none';") { (object : Any?, error : Error?) in

        if (error == nil) {
            let size : CGRect = self.heightForWebView(webView: webView)

            if (weakSelf.webViewHeight == 0.0 || size.height != weakSelf.webViewHeight){
                weakSelf.webViewHeight = size.height
            }

            webView.frame = size
            delegate.updateWebViewCellHeight(height: size.height)
        }
    }
}

// MARK: - WKWebView Heplper
func heightForWebView(webView : WKWebView)-> CGRect {
    var rect : CGRect = webView.frame as CGRect!
    rect.size.height = 1
    webView.frame = rect

    let newSize : CGSize = webView.sizeThatFits(CGSize.zero)
    rect.size = newSize

    return rect
}
Arsalan
  • 150
  • 1
  • 11