forked from shadowfacts/shadowfacts.net
42 lines
2.5 KiB
Markdown
42 lines
2.5 KiB
Markdown
|
```
|
||
|
metadata.title = "Re-Fixing WKWebView Scroll Indicators"
|
||
|
metadata.tags = ["swift"]
|
||
|
metadata.date = "2022-01-30 21:23:42 -0400"
|
||
|
metadata.shortDesc = "Swizzling wasn't worth it, I should have just waited a few more weeks."
|
||
|
metadata.slug = "wkwebview-scroll-indicators-again"
|
||
|
```
|
||
|
|
||
|
As my luck would have it, just a few weeks after I published my [last post](/2022/wkwebview-scroll-indicators/) on this topic, the iOS 15.4 beta came out which broke that hack and once again made my scroll indicators invisible in dark mode.
|
||
|
|
||
|
<!-- excerpt-end -->
|
||
|
|
||
|
Some time ago, a bug was filed against WebKit because setting `scrollIndicatorStyle` on a web view's scroll view was broken on iOS 15. The fix for this bug landed in iOS 15.4 and it subtly changed the behavior of WKScrollView when it comes to the indicator style.
|
||
|
|
||
|
The bug was fixed by tracking whether the web view client has overriden the scroll indicator style and, if so, blocking the web view from resetting it internally. Unfortunately, it [does this](https://github.com/WebKit/WebKit/blob/1dbd34cf01d8b5aedcb8820b13cb6553ed60e8ed/Source/WebKit/UIProcess/ios/WKScrollView.mm#L247) by checking if the new indicator style is not `.default`. So, even if you set it to `.default` to make it automatically switch based on system appearance, the scroll view will interpret that to mean it the indicator style hasn't been overriden and continue erroneously setting it based on background color (or, in my case, the non-opaqueness of the web view).
|
||
|
|
||
|
The solution is simple, if annoying. You need to check the current user interface style and select the appropriate scroll indicator style yourself.
|
||
|
|
||
|
```swift
|
||
|
override func viewWillAppear(_ animated: Bool) {
|
||
|
super.viewWillAppear(animated)
|
||
|
updateScrollIndicatorStyle()
|
||
|
}
|
||
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||
|
super.traitCollectionDidChange(previousTraitCollection)
|
||
|
updateScrollIndicatorStyle()
|
||
|
}
|
||
|
private func updateScrollIndicatorStyle() {
|
||
|
guard #available(iOS 15.4, *) else {
|
||
|
// different workaround pre-iOS 15.4
|
||
|
return
|
||
|
}
|
||
|
if traitCollection.userInterfaceStyle == .dark {
|
||
|
webView.scrollView.indicatorStyle = .white
|
||
|
} else {
|
||
|
webView.scrollView.indicatorStyle = .black
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
And, if you, like me were previously using the old, swizzling workaround, you need to disable in on iOS 15.4. If the old workaround remains active, studiously setting the indicator style to `.default` whenever WebKit would override it, it would merely undo all of our hard work.
|