I want to make a custom browser working with ARKit in background. I set UINavigationController
as rootViewController and push a custom controller WebViewController
in the navigation stack. WebViewController
creates WKWebView
and ARSCNView
and pushes them in its view hierarchy. WKWebView
and ARSCNView
are laid out using auto layout constraints. I also added navigation bar and tool bar for webpage navigating UI with auto show/hide on swiping.
class WebpageViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Set up navigation bar and tool bar
navigationController!.interactivePopGestureRecognizer?.isEnabled = false
navigationController!.hidesBarsOnSwipe = true
navigationController!.delegate = self
...
// Set up ARSCNView and WKWebView
arscnView = ARSCNView(frame: .zero)
arscnView.translatesAutoresizingMaskIntoConstraints = false
arscnView.session.delegate = self
arscnView.showsStatistics = false
arscnView.scene = SCNScene()
view.addSubview(arscnView)
let config = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: config)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
webView.backgroundColor = .clear
view.addSubview(webView)
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
NSLayoutConstraint.activate([
arscnView.topAnchor.constraint(equalTo: view.topAnchor),
arscnView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
arscnView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
arscnView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
}
View hierarchy in xcode
This auto layout constraints looks well in a normal case with auto hiding/showing navigation bar and tool bar.
Normal case
However, at a specific webpage webview does not cover full screen. I found this phenomenon with aframe and I think this is due to <meta name='viewport' content='viewport-fit=cover'>
(this tag automatically injected by aframe)
Abnormal case (when enter aframe page, the navigation bar and tool bar are automatically hidden)
I tried several solutions to handle this issue.
- set
webView.scrollView.contentInsetAdjustmentBehavior = .never
This looks good at a first glance, but I found that webview is obscured by navigation bar and tool bar
webview is obscured by navigation bar and tool bar
- The height of the white area in the bottom looks the summation of navigation bar and tool bar, so I tried to remove safe area when the bars are hidden by overriding
safeAreaInsets
of WKWebVIew.
class MyWebView: WKWebView {
override var safeAreaInsets: UIEdgeInsets {
var insets = UIEdgeInsets()
insets.top = super.safeAreaInsets.top
insets.bottom = super.safeAreaInsets.bottom
insets.left = super.safeAreaInsets.left
insets.right = super.safeAreaInsets.right
// When navigation bar and tool bar are hidden
if window?.safeAreaInsets == superview?.safeAreaInsets {
insets.top = 0
insets.bottom = 0
}
return UIEdgeInsets(top: insets.top, left: insets.left, bottom: insets.bottom, right: insets.right)
}
}
...
// webView = WKWebView(frame: .zero, configuration: config)
webView = MyWebView(frame: .zero, configuration: config)
This still does not work.
- I tried set auto layout constraints at contentView of webView.scrollView
// After setting constraints of WKWebView and ARSCNView
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
...
// Get contentView of webView.scrollView
guard let WKContentViewClass = NSClassFromString("WKContentView") else {
print("Cannot find the WKContentView class")
return
}
let WKContentViewClassName = NSStringFromClass(WKContentViewClass)
guard let contentView = webView.scrollView.subviews.filter({ String(describing: type(of:$0)) == WKContentViewClassName }).first else {
print("Cannot find the WKContentView instance")
return
}
// Set auto layout constraints on contentView
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
contentView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
...
This still not works. This not change its height.
I got stuck this issue for weeks but still can not solve. Auto layout and safe area are too dizzy. How can I achieve the desired work of webview?
What I want to get is like this. the webview automatically adjust its position and height according to the navigation bar's transformation. And home indicator does not occupy any area.