11

I have a custom keyboard with a WKWebView in full width and height. I have disabled the scroll via wkWebView!.scrollView.scrollEnabled = false but I still have a strange scroll behavior at double-tap on the bottom of the WKWebView. Here the source-code of the simple webpage I try to load : http://is.gd/gt8h2q (very simple, just a div full screen with background green and one line of text). Below, a GIF as explanation. Here is how I create the WKWebView :

class KeyboardViewController: UIInputViewController, WKScriptMessageHandler {
var wkWebView: WKWebView?

override func loadView() {
    super.loadView()

    let contentController = WKUserContentController()
    contentController.addScriptMessageHandler(self, name:"callbackTestOne")

    let config = WKWebViewConfiguration()
    config.userContentController = contentController

    self.wkWebView = WKWebView(frame:self.view.frame, configuration:config)
    self.view = self.wkWebView!
}

override func viewDidLoad() {
    super.viewDidLoad()

    (...)

    wkWebView!.scrollView.bounces = false
    wkWebView!.scrollView.scrollEnabled = false
    wkWebView!.scrollView.backgroundColor = UIColor(red:248, green:248, blue:248, alpha:1)
    wkWebView!.scrollView.opaque = true
    wkWebView!.scrollView.showsHorizontalScrollIndicator = false
    wkWebView!.scrollView.showsVerticalScrollIndicator = false
    wkWebView!.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal
}

(...)

GIF explanation

Beny
  • 870
  • 1
  • 15
  • 26
  • 1
    Still unresolved problem... I found a dirty way to fix : in my local loaded page, I use jQuery to auto-scroll to top when scroll position is > 0. Code : `$(window).scroll(function() { if ( $(window).scrollTop() > 0 ) { $(window).scrollTop(0); }; });` – Beny Oct 14 '15 at 14:02
  • This is a real problem. The same thing happens when adding a WKWebView to an iMessage app or extension. – quemeful Feb 03 '17 at 16:02

5 Answers5

9

I had a similar problem and found a solution. That is, to remove the UITapGestureRecognizer that is responsible for the misbehavior.

The WKWebView, or more precisely the UIScrollView and it's subviews that are contained in the WKWebView, have a lot of gesture recognizers added. So you can easily iterate over all of those recognizers in the views and remove the one you need.

If you want to remove all 1-finger double-tap recognizers from the webView, you need to search inside the subviews of the scroll view. You could do the following:

// iterate over all subviews of the WKWebView's scrollView
for subview in _webView.scrollView.subviews {

    // iterate over recognizers of subview
    for recognizer in subview.gestureRecognizers ?? [] {

        // check the recognizer is  a UITapGestureRecognizer
        if recognizer.isKind(of: UITapGestureRecognizer.self) {

            // cast the UIGestureRecognizer as UITapGestureRecognizer
            let tapRecognizer = recognizer as! UITapGestureRecognizer

            // check if it is a 1-finger double-tap
            if tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {

                // remove the recognizer
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }
}

This should fix your problem.

Yves Tscherry
  • 99
  • 1
  • 3
5

Hacky and dirty solution. But at least it works. Just add your own UITapGestureRecognizer to a view contained WKWebView and make your UIViewController delegate to this gesture recognizer. I used this code:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([[otherGestureRecognizer description] containsString:@"WKSyntheticClickTapGestureRecognizer"] && [[otherGestureRecognizer description] containsString:@"numberOfTapsRequired = 2"]) {
        [otherGestureRecognizer removeTarget:nil action:nil];
        return YES;
    }

Update 1 After some investigations I found out that this approach is not so good. Coz we have problems with long press menu especially with deselecting selected text. And there was still issue for me - do a long tap when menu appear slightly swipe left or right - sometimes WKWebView could start scroll. Next approach is in setting WKSelectionGranularityCharacter for WKWebViewConfiguration - this is not obvious I must say (Apple why are you doing this?) So then it works fine on iOS8 - there is no double tap, every gesture works as it should be. However for iOS9 we have bad news - http://www.openradar.me/23345435 It was broken. So continue to investigate.

Zayin Krige
  • 2,931
  • 1
  • 29
  • 31
0

This is refactored version, written in Swift 4.2 Just pass your WKWebView as a parameter and call the function somewhere like viewDidLoad.

private func deleteDoubleTap(web: WKWebView) {
    for subview in web.scrollView.subviews {            
        let recognizers = subview.gestureRecognizers?.filter{$0 is UITapGestureRecognizer}
        recognizers?.forEach{recognizer in
            let tapRecognizer = recognizer as! UITapGestureRecognizer
            if tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }

}
Roman
  • 144
  • 1
  • 11
0

The same idea as there https://stackoverflow.com/a/42939172/2883860 but a little more modern.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.scrollView.subviews.forEach { subview in
        subview.gestureRecognizers?.forEach { recognizer in
            if let tapRecognizer = recognizer as? UITapGestureRecognizer,
                tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }
}
pchelnikov
  • 281
  • 3
  • 6
-2

Assuming you are under control of the content that you display in that WKWebView, you should set the right viewport for it. That will most likely disable this behaviour.

How about:

<meta id="viewport" name="viewport"
    content="width=device-width; user-scalable=false" />
Stefan Arentz
  • 31,710
  • 8
  • 65
  • 87