Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable double-tap scroll on WKWebView

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

like image 965
Beny Avatar asked Oct 13 '15 20:10

Beny


3 Answers

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)
            }
        }
    }
}
like image 180
pchelnikov Avatar answered Nov 20 '22 09:11

pchelnikov


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.

like image 32
Alexander Slabinsky Avatar answered Nov 20 '22 09:11

Alexander Slabinsky


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.

like image 10
Yves Tscherry Avatar answered Nov 20 '22 08:11

Yves Tscherry