Merge pull request #924 from correia/correia/white-flash-on-load
Fix flash on white when loading detail view controller in dark mode
This commit is contained in:
commit
8335a5cb48
|
@ -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 {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14854.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14806.4"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -15,22 +15,13 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<wkWebView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="t8d-md-Yhc">
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DNb-lt-KzC">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="769"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<wkWebViewConfiguration key="configuration">
|
||||
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
|
||||
<wkPreferences key="preferences"/>
|
||||
</wkWebViewConfiguration>
|
||||
</wkWebView>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="t8d-md-Yhc" firstAttribute="top" secondItem="VUw-jc-0yf" secondAttribute="top" id="0aK-ew-1HG"/>
|
||||
<constraint firstItem="VUw-jc-0yf" firstAttribute="trailing" secondItem="t8d-md-Yhc" secondAttribute="trailing" id="31v-r8-kzh"/>
|
||||
<constraint firstItem="VUw-jc-0yf" firstAttribute="bottom" secondItem="t8d-md-Yhc" secondAttribute="bottom" id="kK6-eC-XwD"/>
|
||||
<constraint firstItem="t8d-md-Yhc" firstAttribute="leading" secondItem="VUw-jc-0yf" secondAttribute="leading" id="nDG-aV-vqc"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="VUw-jc-0yf"/>
|
||||
</view>
|
||||
<toolbarItems>
|
||||
|
@ -112,7 +103,7 @@
|
|||
<outlet property="prevArticleBarButtonItem" destination="v4j-fq-23N" id="Gny-Oh-cQa"/>
|
||||
<outlet property="readBarButtonItem" destination="hy0-LS-MzE" id="BzM-x9-tuj"/>
|
||||
<outlet property="starBarButtonItem" destination="wU4-eH-wC9" id="Z8Q-Lt-dKk"/>
|
||||
<outlet property="webView" destination="t8d-md-Yhc" id="Iqg-bg-wds"/>
|
||||
<outlet property="webViewContainer" destination="DNb-lt-KzC" id="Fc1-Ae-pWK"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
|
||||
|
|
|
@ -14,23 +14,42 @@ import SafariServices
|
|||
|
||||
class DetailViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var prevArticleBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var nextArticleBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var readBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var starBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var actionBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var browserBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var webView: WKWebView!
|
||||
|
||||
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var readBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var starBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var actionBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var browserBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet private weak var webViewContainer: UIView!
|
||||
private var webView: WKWebView!
|
||||
|
||||
weak var coordinator: AppCoordinator!
|
||||
|
||||
deinit {
|
||||
webView.removeFromSuperview()
|
||||
DetailViewControllerWebViewProvider.shared.enqueueWebView(webView)
|
||||
webView = nil
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
webView.isHidden = true
|
||||
|
||||
webView = DetailViewControllerWebViewProvider.shared.dequeueWebView()
|
||||
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||
webView.navigationDelegate = self
|
||||
|
||||
webViewContainer.addSubview(webView)
|
||||
|
||||
let constraints: [NSLayoutConstraint] = [
|
||||
webView.leadingAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.leadingAnchor),
|
||||
webView.trailingAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.trailingAnchor),
|
||||
webView.topAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.topAnchor),
|
||||
webView.bottomAnchor.constraint(equalTo: webViewContainer.safeAreaLayoutGuide.bottomAnchor),
|
||||
]
|
||||
|
||||
NSLayoutConstraint.activate(constraints)
|
||||
|
||||
markAsRead()
|
||||
updateUI()
|
||||
reloadHTML()
|
||||
|
@ -213,16 +232,6 @@ extension DetailViewController: WKNavigationDelegate {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
// We initially hide the webview and only show it after it has loaded to avoid the
|
||||
// white flashing that WKWebView does when it loads. This is especially noticable
|
||||
// in dark mode.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
|
||||
webView.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension DetailViewController {
|
||||
|
@ -234,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue