WKWebview allowsBackForwardNavigationGestures and UINavigationController interactivePopGestureRecognizer both enabled
Asked Answered
C

4

6

My View Controller embedded inside a navigation controller holds a WKWebview on which I want to enable the following logic:

If a back item exists in the webview, making a left screen edge gesture should go back one page in the webview (normal behaviour of webview when allowsBackForwardNavigationGestures is set to yes). When there isnt any back item, it should pop one page in the navigation controller (interactivePopGestureRecognizer). I enabled both and I get random results, sometimes I go back one page in the webview and sometimes I go back to my home page in the navigation stack. I tried the following logic:

-(void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {

  if (webView.backForwardList.backItem) {
    MYappDelegate.mainNavigationController.interactivePopGestureRecognizer.enabled = NO;
    self.webView.allowsBackForwardNavigationGestures = YES;
  } else {
    MYappDelegate.mainNavigationController.interactivePopGestureRecognizer.enabled = YES;
    self.webView.allowsBackForwardNavigationGestures = NO;
  }
}

but it crashes when I swipe and I get "WKCompositingView unrecognized selector sent to instance."

Any ideas where I'm going wrong? Im guessing there is a conflict regarding which gesture takes priority but I cant figure out where to add this logic so both the webview and the navigation controller containing its view controller live peacefully.

Camus answered 21/7, 2016 at 9:29 Comment(1)
for later iOS versions it seems that navigation gesture overrides the wkwebview one, so the webview interaction should allways be true and it's only matter of disabling the navigation gesture if the user is on the first page or not.Lambency
P
1

I have a same issue. Please try the following way:

Firstly, add a custom gesture to the WebView:

    let swipe = UISwipeGestureRecognizer(target: self, action: #selector(goBack))
    swipe.direction = UISwipeGestureRecognizerDirection.right
    swipe.delegate = self.navigationController
    webView.addGestureRecognizer(swipe)

then, add a UIGestureDelegate method to deal with gesture simultaneously,

extension UINavigationController: UIGestureRecognizerDelegate{
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return gestureRecognizer is UIScreenEdgePanGestureRecognizer
}

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

}

But it has a minor defect that swiping effect differs from native one, which show new viewController when swiping without touch up.

Peddada answered 8/10, 2016 at 9:30 Comment(0)
C
3
_webView.allowsBackForwardNavigationGestures = YES;

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    self.navigationController.interactivePopGestureRecognizer.enabled = _webView.canGoBack ? NO : YES;
}
Culinary answered 1/3, 2021 at 7:59 Comment(1)
Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please edit your question and explain how it works better than what the OP provided. See How to Answer.Scudo
P
1

I have a same issue. Please try the following way:

Firstly, add a custom gesture to the WebView:

    let swipe = UISwipeGestureRecognizer(target: self, action: #selector(goBack))
    swipe.direction = UISwipeGestureRecognizerDirection.right
    swipe.delegate = self.navigationController
    webView.addGestureRecognizer(swipe)

then, add a UIGestureDelegate method to deal with gesture simultaneously,

extension UINavigationController: UIGestureRecognizerDelegate{
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return gestureRecognizer is UIScreenEdgePanGestureRecognizer
}

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

}

But it has a minor defect that swiping effect differs from native one, which show new viewController when swiping without touch up.

Peddada answered 8/10, 2016 at 9:30 Comment(0)
M
1

maybe you can use an observer for canGoback, like

RACObserve(self.wk_webView, canGoBack)

if the value is true, do

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Musa answered 4/6, 2018 at 8:51 Comment(0)
I
0
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, UIGestureRecognizerDelegate {

    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        webView = WKWebView(frame: self.view.bounds)
        webView.navigationDelegate = self
        // Step1: enable webview right-swipe to return the previous URL
        webView.allowsBackForwardNavigationGestures = true
        self.view.addSubview(webView)
        
        if let url = URL(string: "https://example.com") {
            let request = URLRequest(url: url)
            webView.load(request)
        }
        
        // Step2: control whether right-swipe to popViewController in gestureRecognizerShouldBegin function
        self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    }

    // Step3: if webView cannot go back, enable interactivePopGestureRecognizer(right-swipe to popViewController)
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return !(webView.canGoBack)
    }

    // Step4: when webView finish load, determine whether the interaction gesture of navigationController is enabled
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.navigationController?.interactivePopGestureRecognizer?.isEnabled = !webView.canGoBack
    }
}
Inadequate answered 25/10 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.