Search code examples
iosswiftuiwebviewuigesturerecognizeruipageviewcontroller

Pass ScreenEdgePanGesture on UIWebView to parent PageViewController


I am embedding Google Maps for navigation in a full-width UIWebView that is itself embedded in a UIPageViewController (in scroll mode). The page controller responds to the page turn gesture on all pages, even inside the UIWebView, unless the UIWebView has Google Maps loaded. Obviously, this is because the web page has intercepted the pan/swipe gesture. I wish to allow all panning and interaction inside the web page except if the gesture is an edge swipe. A pan gesture near the edge is also acceptable if edge swiping is not possible.

I can add a ScreenEdgePanGestureRecognizer and segue to a page but this puts me outside the UIPageView. I would like the solution to be expandable, in that it does not segue to a specific page (with pageViewController.setViewControllers for example) but just allows the UIPageViewController to transition to the next/previous page.

Here is how I am intercepting the gesture currently.

    var leftScreenPanGestureRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(self.handleMapSwipe(_:)))
    leftScreenPanGestureRecognizer.edges = .Left
    leftScreenPanGestureRecognizer.cancelsTouchesInView = true
    self.view.addGestureRecognizer(leftScreenPanGestureRecognizer)
    self.webView.addGestureRecognizer(leftScreenPanGestureRecognizer)


    if let location = locationManager.location?.coordinate {
        let lat = location.latitude
        let long = location.longitude
        webView.loadRequest(NSURLRequest(URL: NSURL(string: "https://www.google.com/maps/place/\(lat),\(long)/")!))
    } else {
        webView.loadRequest(NSURLRequest(URL: NSURL(string: "https://www.google.com/maps/")!))
    }

Question is: How to allow the UIPageViewController to intercept only the relevant gestures. Or to intercept the gesture then pass it to the UIPageViewController in an expandable way.


Solution

  • I found a way to handle this in an expandable way after learning about self.parentViewController

    @IBAction func handleMapBackwardSwipe(recognizer: UIScreenEdgePanGestureRecognizer) {
        if (recognizer.state == .Began) {
            webView.scrollView.scrollEnabled = true
        } else if(recognizer.state == .Ended || recognizer.state == .Cancelled){
            webView.scrollView.scrollEnabled = false
        }
    
        // PageViewController is the controlling class for the UIPageViewController on the storyboard.
        let pvc = (self.parentViewController as! PageViewController)
        let newView = pvc.pageViewController(pvc, viewControllerBeforeViewController: self)
        if let newView = newView {
            pvc.setViewControllers([newView], direction: .Reverse, animated: true, completion: nil)
        }
    }
    
    @IBAction func handleMapForwardSwipe(recognizer: UIScreenEdgePanGestureRecognizer) {
        if (recognizer.state == .Began) {
            webView.scrollView.scrollEnabled = true
        } else if(recognizer.state == .Ended || recognizer.state == .Cancelled){
            webView.scrollView.scrollEnabled = false
        }
    
        let pvc = (self.parentViewController as! PageViewController)
        let newView = pvc.pageViewController(pvc, viewControllerAfterViewController: self)
        if let newView = newView {
            pvc.setViewControllers([newView], direction: .Forward, animated: true, completion: nil)
        }
    }