title: How do I use 2 gesture recognizers to receive events simultaneously?
body: <p>I'm using swipe gestures to navigate between tabs using a fake UITabBarController that hosts 4 UIViewController subclasses inside of a UIScrollView, with UIPanGestureRecognizers on each of them to detect swipes and switch tabs accordingly. The resulting effect is core navigation like what you see on Snapchat. However, one of these screens houses a map view (Mapbox map), which has its own gesture recognizers built-in.</p>
  
  <p>I'd like for the user to be able to swipe on the map itself to navigate to another tab by detecting a swipe from the very right edge of the screen. I've tried adding a UIPanGestureRecognizer to an invisible UIView in this area on the right side, but this provides for a jerky, unanimated tab switch, and it intercepts touch events from the map below.</p>
  
  <p>How can I allow for both gesture recognizers to receive events simultaneously, or filter out some events based upon only the start position of the swipe and its distance and direction?</p>
  
  <p><strong>Code for swiping view controller:</strong></p>
  
  <pre><code>class KUSwipeViewController: EZSwipeController {
  
      fileprivate var fakeTabBar: UIView!
  
      fileprivate var tabBarHeight: CGFloat = 50
  
      override func viewDidLoad() {
          initUI()
      }
  
      override func setupView() {
          super.setupView()
          datasource = self
          navigationBarShouldNotExist = true
      }
  
      func initUI() {
          fakeTabBar = UIView(frame: CGRect(x: 0, y: Screen.height - tabBarHeight, width: Screen.width, height: tabBarHeight))
          fakeTabBar.backgroundColor = .black
  
          let tab0 = UIButton(frame: CGRect(x: Screen.width * 0.08, y: 9, width: 32, height: 32))
          tab0.setBackgroundImage(#imageLiteral(resourceName: "tab-events"), for: .normal)
          tab0.addTarget(self, action: #selector(tapped0), for: .touchUpInside)
          fakeTabBar.addSubview(tab0)
  
          let tab1 = UIButton(frame: CGRect(x: Screen.width * 0.32, y: 9, width: 32, height: 32))
          tab1.setBackgroundImage(#imageLiteral(resourceName: "tab-feat"), for: .normal)
          tab1.addTarget(self, action: #selector(tapped1), for: .touchUpInside)
          fakeTabBar.addSubview(tab1)
  
          let tab2 = UIButton(frame: CGRect(x: Screen.width * 0.58, y: 9, width: 32, height: 32))
          tab2.setBackgroundImage(#imageLiteral(resourceName: "tab-chat"), for: .normal)
          tab2.addTarget(self, action: #selector(tapped2), for: .touchUpInside)
          fakeTabBar.addSubview(tab2)
  
          let tab3 = UIButton(frame: CGRect(x: Screen.width * 0.82, y: 9, width: 32, height: 32))
          tab3.setBackgroundImage(#imageLiteral(resourceName: "tab-profile"), for: .normal)
          tab3.addTarget(self, action: #selector(tapped3), for: .touchUpInside)
          fakeTabBar.addSubview(tab3)
  
          view.addSubview(fakeTabBar)
      }
  
  
      func tapped0() {
          self.moveToPage(0, animated: true)
      }
  
      func tapped1() {
          self.moveToPage(1, animated: true)
      }
  
      func tapped2() {
          self.moveToPage(2, animated: true)
      }
  
      func tapped3() {
          self.moveToPage(3, animated: true)
      }
  }
  
  extension KUSwipeViewController: EZSwipeControllerDataSource {
      func viewControllerData() -&gt; [UIViewController] {
  
          let nav0 = UINavigationController()
          let nav3 = UINavigationController()
  
          let mapVC = EventMapViewController()
          let featuredVC = FeaturedEventsViewController()
          let chatVC = MessagesViewController()
          let profileVC = ProfileViewController()
  
          nav0.viewControllers = [mapVC]
          nav3.viewControllers = [profileVC]
  
          return [nav0, featuredVC, chatVC, nav3]
      }
  
      func titlesForPages() -&gt; [String] {
          return ["", "", "", ""]
      }
  
      func indexOfStartingPage() -&gt; Int {
          return 0
      }
  
      func changedToPageIndex(_ index: Int) {
          Haptic.selection.generate()
      }
  }
  </code></pre>
  
  <p><strong>Code for map view controller:</strong></p>
  
  <pre><code>class EventMapViewController: CommonViewController {
  
      fileprivate var mapView: MGLMapView!
      fileprivate var statusBarView: UIView!
      fileprivate var searchBar: FloatingSearchBar!
      fileprivate var searchButton: UIButton!
      fileprivate var filterButton: UIButton!
      fileprivate var peekView: UIView!
      fileprivate var architectView: UIView!
      fileprivate var panArchitectView: UIView!
      fileprivate var peekArchitectView: UIView!
      fileprivate var peekLabel: UILabel!
      fileprivate var panView: UIPanGestureRecognizer!
  
      fileprivate let peekViewHeight: CGFloat = 140
  
      fileprivate var selectedEvent: Event?
  
      fileprivate var cardShowing: Bool = false
      fileprivate var peekShowing: Bool = false
  
      /*
      override func statusBarStyle() -&gt; UIStatusBarStyle {
          return cardShowing ? .lightContent : .default
      }
      */
  
      override func navigationBarHidden() -&gt; Bool {
          return true
      }
  
      override func viewDidLoad() {
          super.viewDidLoad()
          initUI()
      }
  
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          if segue.identifier == "eventSegue" {
              let dvc = segue.destination as! EventViewController
              dvc.event = selectedEvent!
          }
      }
  
      func initUI() {
          mapView = MGLMapView(frame: view.bounds)
          mapView.styleURL = (UIColor.theme == .light) ? URL(string: mbThemeLight)! : URL(string: mbThemeDark)!
          mapView.showsUserLocation = true
          mapView.userTrackingMode = .none
          mapView.delegate = self
          mapView.setCenter(CLLocationCoordinate2D(latitude: 34, longitude: -118), zoomLevel: 5, animated: false)
          view.addSubview(mapView)
          mapView.snp.makeConstraints { (make) in
              make.edges.equalTo(view)
          }
  
          //architect view (for intercepting touch)
          architectView = UIView(frame: self.view.bounds)
          let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EventMapViewController.handleTap(gestureRecognizer:)))
          gestureRecognizer.delegate = self
          architectView.addGestureRecognizer(gestureRecognizer)
          architectView.isHidden = true
          view.addSubview(architectView)
  
          statusBarView = UIView()
          statusBarView.backgroundColor = UIColor.clear
          view.addSubview(statusBarView)
          statusBarView.snp.makeConstraints { (make) in
              make.left.right.top.equalTo(0)
              make.height.equalTo(20)
          }
  
          searchButton = UIButton()
          searchButton.backgroundColor = UIColor.kuLightBackground
          searchButton.tintColor = (UIColor.theme == .light) ? UIColor.kuPrimary : UIColor.kuDeselected
          searchButton.setImage(#imageLiteral(resourceName: "icon_search_white").withRenderingMode(.alwaysTemplate), for: .normal)
          searchButton.layer.cornerRadius = 25
          searchButton.layer.borderColor = UIColor.kuExtraLightBackground.cgColor
          searchButton.layer.borderWidth = 1
          searchButton.addTarget(self, action: #selector(searchButtonTapped(_:)), for: .touchUpInside)
          view.addSubview(searchButton)
          searchButton.snp.makeConstraints { (make) in
              make.width.height.equalTo(50)
              make.left.equalTo(24)
              make.top.equalTo(34)
          }
  
          filterButton = UIButton()
          filterButton.backgroundColor = UIColor.kuLightBackground
          filterButton.tintColor = (UIColor.theme == .light) ? UIColor.kuPrimary : UIColor.kuDeselected
          filterButton.setImage(#imageLiteral(resourceName: "icon_filter_white").withRenderingMode(.alwaysTemplate), for: .normal)
          filterButton.layer.cornerRadius = 20
          filterButton.layer.borderColor = UIColor.kuExtraLightBackground.cgColor
          filterButton.layer.borderWidth = 1
          filterButton.addTarget(self, action: #selector(filterButtonTapped(_:)), for: .touchUpInside)
          view.addSubview(filterButton)
          filterButton.snp.makeConstraints { (make) in
              make.width.height.equalTo(40)
              make.left.equalTo(80)
              make.top.equalTo(40)
          }
  
          //peek view
          peekView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height, width: UIScreen.main.bounds.width, height: peekViewHeight))
          peekView.backgroundColor = UIColor(white: 1, alpha: 0.5)
          peekView.layer.cornerRadius = 10
          view.addSubview(peekView)
  
          //peek label
          peekLabel = UILabel(frame: CGRect(x: 0, y: 12, width: UIScreen.main.bounds.width, height: 68))
          peekLabel.font = UIFont.kuBoldFont(ofSize: 38)
          peekLabel.textColor = .black
          peekLabel.textAlignment = .center
          peekView.addSubview(peekLabel)
  
          //peek architect
          peekArchitectView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: peekViewHeight))
          let peekGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EventMapViewController.peekSelected(gestureRecognizer:)))
          peekGestureRecognizer.delegate = self
          peekArchitectView.addGestureRecognizer(peekGestureRecognizer)
          peekView.addSubview(peekArchitectView)
  
          loadEventAnnotations()
      }
  
      func enterPeekView() {
          guard !peekShowing else { return }
  
          architectView.isHidden = false
          peekLabel.text = "\(selectedEvent!.title!) &gt;"
  
          peekView.cheetah
              .move(0, peekViewHeight * -1)
              .duration(0.18)
              .easeOutExpo
              .run()
  
          peekShowing = true
      }
  
      func exitPeekView() {
          guard peekShowing else { return }
  
          architectView.isHidden = true
          peekView.cheetah
              .move(0, peekViewHeight)
              .duration(0.18)
              .easeInExpo
              .run()
  
          peekShowing = false
      }
  
      func loadEventAnnotations() {
          RealmManager.shared.defaultRealm.objects(Event.self).forEach { (event) in
  
              let annotation = EventAnnotation()
              annotation.event = event
              mapView.addAnnotation(annotation)
          }
      }
  
      func searchButtonTapped(_ sender: UIButton) {
          let eventSearchCardViewController = EventSearchCardViewController()
          eventSearchCardViewController.delegate = self
          UIApplication.rootViewController()?.presentCardViewController(eventSearchCardViewController)
      }
  
      func filterButtonTapped(_ sender: UIButton) {
          let eventFilterCardViewController = EventFilterCardViewController()
          eventFilterCardViewController.delegate = self
          UIApplication.rootViewController()?.presentCardViewController(eventFilterCardViewController)
      }
  }
  
  extension EventMapViewController: CardViewControllerDelegate {
  
      func cardViewControllerWillAppear(cardViewController: CardViewController) {
          cardShowing = true
          setNeedsStatusBarAppearanceUpdate()
      }
  
      func cardViewControllerWillDisappear(cardViewController: CardViewController) {
          cardShowing = false
          setNeedsStatusBarAppearanceUpdate()
      }
  }
  
  extension EventMapViewController: MGLMapViewDelegate {
  
      func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
  
          guard let eventAnnotation = annotation as? EventAnnotation else {
              return
          }
  
          selectedEvent = eventAnnotation.event
  
          enterPeekView()
      }
  
      func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -&gt; Bool {
          return false
      }
  
      func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -&gt; MGLAnnotationImage? {
          var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: UIColor.kuMarkerName)
  
          if annotationImage == nil {
              var image = UIImage(named: UIColor.kuMarkerName)!
              image = image.withAlignmentRectInsets(UIEdgeInsets(top: 0, left: 0, bottom: image.size.height/2, right: 0))
              annotationImage = MGLAnnotationImage(image: image, reuseIdentifier: UIColor.kuMarkerName)
          }
  
          return annotationImage
      }
  }
  
  extension EventMapViewController: UIGestureRecognizerDelegate {
  
      func handleTap(gestureRecognizer: UIGestureRecognizer) {
          //close peek and keyboard on tap
          view.endEditing(true)
  
          if peekShowing {
              exitPeekView()
          }
      }
  
      func peekSelected(gestureRecognizer: UIGestureRecognizer) {
  //        performSegue(withIdentifier: "eventSegue", sender: nil)
  
          let eventController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EventViewController") as! EventViewController
          self.navigationController?.pushViewController(eventController, animated: true)
      }
  }
  </code></pre>