Maintain a queue of "prepared" web views for use in DetailWebViewController.

WKWebView has an awful behavior of a flash to white on first load when in
dark mode.

Keep a queue of WebViews where we've already done a trivial load so that by
the time we need them in the UI, they're past the flash-to-shite part of
their lifecycle.
This commit is contained in:
Jim Correia 2019-08-31 12:53:03 -07:00
parent a5b2c759ec
commit f7b53283d6
2 changed files with 55 additions and 1 deletions

View File

@ -237,6 +237,9 @@ class AppCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(accountDidDownloadArticles(_:)), name: .AccountDidDownloadArticles, object: nil)
// Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views
let _ = DetailViewControllerWebViewProvider.shared
}
func start() -> UIViewController {

View File

@ -26,10 +26,16 @@ class DetailViewController: UIViewController {
weak var coordinator: AppCoordinator!
deinit {
webView.removeFromSuperview()
DetailViewControllerWebViewProvider.shared.enqueueWebView(webView)
webView = nil
}
override func viewDidLoad() {
super.viewDidLoad()
webView = WKWebView(frame: webViewContainer.bounds)
webView = DetailViewControllerWebViewProvider.shared.dequeueWebView()
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
@ -237,3 +243,48 @@ private extension DetailViewController {
}
}
// MARK: -
/// WKWebView has an awful behavior of a flash to white on first load when in dark mode.
/// Keep a queue of WebViews where we've already done a trivial load so that by the time we need them in the UI, they're past the flash-to-shite part of their lifecycle.
class DetailViewControllerWebViewProvider {
static var shared = DetailViewControllerWebViewProvider()
func dequeueWebView() -> WKWebView {
if let webView = queue.popLast() {
replenishQueueIfNeeded()
return webView
}
assertionFailure("Creating WKWebView in \(#function); queue has run dry.")
let webView = WKWebView(frame: .zero)
return webView
}
func enqueueWebView(_ webView: WKWebView) {
webView.uiDelegate = nil
webView.navigationDelegate = nil
let html = ArticleRenderer.noSelectionHTML(style: .defaultStyle)
webView.loadHTMLString(html, baseURL: nil)
queue.insert(webView, at: 0)
}
// MARK: Private
private let minimumQueueDepth = 3
private var queue: [WKWebView] = []
private init() {
replenishQueueIfNeeded()
}
private func replenishQueueIfNeeded() {
while queue.count < minimumQueueDepth {
let webView = WKWebView(frame: .zero)
enqueueWebView(webView)
}
}
}