Search code examples
swiftxcodeswipegestureswift5

UISwipeGestureRecognizer causes jerkiness


I use UISwipeGestureRecogniser in my UITabBarController:

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.selectedIndex = Values.menuSelectedIndex
        let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
        let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
        leftSwipe.direction = .left
        rightSwipe.direction = .right
        view.addGestureRecognizer(leftSwipe)
        view.addGestureRecognizer(rightSwipe)
    }

    @objc func handleSwipes(_ sender:UISwipeGestureRecognizer) {
        /*if let topController = UIApplication.topViewController() {
            if (topController is HomeVC) {
                if (sender.direction == .left) {
                    self.selectedIndex += 1
                }
                else if (sender.direction == .right) {
                    self.selectedIndex -= 1
                }
            }
        }*/
    }
}

When the topController is anything other than HomeVC, the swipe gesture should do nothing. Unfortunately, it causes jerkiness when scrolling left and right.

Edit

UIApplication.topViewController() is an extension to get the current UIViewController:

extension UIApplication {
    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}

Solution

  • gestureRecognizer:shouldRecognizeSimultaniouslyWith:otherGesture would not work for me because I am using NMAMapViewDelegate and NMAMapGestureDelegate.

    I got this working simply by removing the gesture whenever on a UIViewController that should not be calling handleSwipes.

    In TabBarController I added:

    lazy var leftSwipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
    lazy var rightSwipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
    
    public func addGestures() {
        view.addGestureRecognizer(leftSwipe)
        view.addGestureRecognizer(rightSwipe)
    }
    
    public func removeGestures() {
        view.removeGestureRecognizer(leftSwipe)
        view.removeGestureRecognizer(rightSwipe)
    }
    

    and in any UIViewControllers that should not call handleSwipes:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        (navigationController?.tabBarController as? TabBarController)?.removeGestures()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        (navigationController?.tabBarController as? TabBarController)?.addGestures()
    }