Search code examples
iosswiftuiscrollviewwkwebview

Setting contentInset of WKWebView scrollView causes page jump to top


After setting contentInset of WKWebView, I found if I use default swipe gesture to navigate between pages, WKWebView will not reserve the contentInset and just jump to the top, does anyone know how to resolve that? Thanks!

enter image description here

My sample code:

import UIKit
import WebKit

class ViewController: UIViewController {

    private lazy var webView: WKWebView = {
        let view = WKWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
        view.allowsBackForwardNavigationGestures = true
        view.scrollView.contentInsetAdjustmentBehavior = .never
        view.scrollView.contentInset = UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0)

        view.navigationDelegate = self
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.view.addSubview(self.webView)

        if let url = URL(string: "http://www.wikipedia.org") {
            self.webView.load(URLRequest(url: url))
        }
    }

}

Solution

  • If you set contentInset for a scrollview of WKWebView, you need set another property of WKWebview with same value. view.setValue(UIEdgeInsets, forKey: "_obscuredInsets")

    Refer to : https://opensource.apple.com/source/WebKit2/WebKit2-7600.1.4.11.10/ChangeLog

    private lazy var webView: WKWebView = {
            let view = WKWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
            view.allowsBackForwardNavigationGestures = true
            view.scrollView.contentInsetAdjustmentBehavior = .never
            let edgeInsets = UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0)
            view.setValue(edgeInsets, forKey: "_obscuredInsets")
            view.scrollView.contentInset = edgeInsets
            return view
        }()
    

    If you set contentInsetAdjustmentBehavior = .automatic, there will have a extra edge of status bar. You also need to add the status bar height to obscuredInsets.

    view.scrollView.contentInsetAdjustmentBehavior = . automatic
    webView.scrollView.contentInset = UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0)
    webView.setValue(UIEdgeInsets(top: 50 + 44, left: 0, bottom: 0, right: 0), forKey: "_obscuredInsets")
    

    44 is the height of status bar(safeArea).


    Checked the newest WKWebView: https://github.com/WebKit/webkit/blob/master/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

    Now need add an extra property: _haveSetObscuredInsets

    webView.setValue(true, forKey: "_haveSetObscuredInsets")