Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save YoomamaFTW/333675c0f3a81f46023277ef7aa26217 to your computer and use it in GitHub Desktop.
Save YoomamaFTW/333675c0f3a81f46023277ef7aa26217 to your computer and use it in GitHub Desktop.
WKWebView in a UIView for tableHeaderView that auto-resizes - Swift 5.1
import UIKit
import WebKit
// This gist assumes you already have a UITableView setup
// This gist is designed to look like Reddit's DetailViewController, HOWEVER
// The point of a WKWebView is that images can be loaded
// This gist is NOT perfect; look in comments for what needs to be fixed.
class ViewController: UIViewController, WKNavigationDelegate {
let headerView = UIView()
let titleView = UILabel()
let webView = WKWebView()
let tableView = UITableView()
override func viewDidLoad() {
setupTable() // The table is up for you to set up
setupTableHeader() // Where you will setup that header view
tableView.tableHeaderView = headerView
}
setupTableHeader() {
titleView.translatesAutoresizingMaskIntoConstraints = false
webView.translatesAutoresizingMaskIntoConstraints = false
webView.scrollView.bounces = false
webView.navigationDelegate = self
webView.loadHTMLString(
"""
<header><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'></header>
<b>HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. HI THERE. </b>
<p>The above was just written to test the frame. I am hesitant to have add an img tag</p>
""", with: nil)
// IT IS VITAL THAT YOU HAVE THAT HEADER or else the document's frame isn't correct
webView.configuration.preferences.javaScriptEnabled = false // I have this for XSS or theft protection for users
headerView.addSubview(titleView)
headerView.addSubview(webView)
NSLayoutConstraint.activate([ // THERE IS AN ISSUE HERE with autolayout. I'm not an autolayout expert, so help needed
titleView.topAnchor.constraint(equalTo: headerView.topAnchor),
titleView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
titleView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor),
titleView.bottomAnchor.constraint(equalTo: webView.topAnchor),
webView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor),
webView.bottomAnchor.constraint(equalTo: headerView.bottomAnchor)
])
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// I would like to incorporate this answer
// https://stackoverflow.com/a/41511422
// It deals with images much better since gist this only works when initially loaded. But for images, it won't.
// This will resize the header view to accomodate for the new html.
// If you need animation design, then this is not the right function you should be using.
headerView.translatesAutoresizingMaskIntoConstraints = false
let widthConstraint = NSLayoutConstraint(item: headerView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: tableView.bounds.width)
headerView.addConstraint(widthConstraint)
webView.configuration.preferences.javaScriptEnabled = true
webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
if complete != nil {
self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height1, error) in
let height = self.headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + (height1 as! CGFloat)
self.headerView.frame.size.height = height
self.tableView.tableHeaderView = self.headerView
self.headerView.removeConstraint(widthConstraint)
self.headerView.translatesAutoresizingMaskIntoConstraints = true
self.webView.configuration.preferences.javaScriptEnabled = false
})
}
})
}
}
/*
This took me decades to figure out, but if you can make this more efficient, then here are the resources that helped me
that can help you figure out a better method.
How did I manage to get the WKWebView thing to work? Follow these links:
- Resizing the header view once the html loaded: https://gist.github.com/marcoarment/1105553afba6b4900c10#gistcomment-1933639
- Getting scroll view size of WKWebView to add header view frame height: https://stackoverflow.com/questions/27515236/how-to-determine-the-content-size-of-a-wkwebview
- Making the font normal size since the viewport was wrong: https://stackoverflow.com/questions/45998220/the-font-looks-like-smaller-in-wkwebview-than-in-uiwebview
*/
@YoomamaFTW
Copy link
Author

This took me a couple days to figure out, but eventually I got a WKWebView inside of a tableHeaderView, not a UITableViewCell nor a section header view, but the table's header view. It incorporated a bunch of solutions that are shown at the bottom of the gist.

There are some things to fix though:

  1. The WKNavigationDelegate function that helps with the resizing of the table header view does not work very well with images. This is because the function only runs once (didFinish). I would like to incorporate this answer: https://stackoverflow.com/a/41511422 in order to accommodate for those links to images that take time to load.
  2. There is an issue with auto layout in the setupTableHeader() function. Xcode is still breaking constraints, and it could have something to do with the resizing of the headerView.

Recommendations:

  • With the auto layout, I suggest you include layoutMargins just to look better.
  • Efficiency: I believe having too many WKWebViews can lead to some kind of memory error. I know when I was initially testing this with the Parchment library (with PagingViewController), I was running into some memory issues, but this was before I solved this issue of resizing WKWebView.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment