6
votes

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.

3
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.htafoya

3 Answers

3
votes
_webView.allowsBackForwardNavigationGestures = YES;

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    self.navigationController.interactivePopGestureRecognizer.enabled = _webView.canGoBack ? NO : YES;
}
1
votes

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.

1
votes

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;
}