R
R
Rasul Kakushev2019-07-02 21:50:37
iOS
Rasul Kakushev, 2019-07-02 21:50:37

How to make swipe gesture work in uinavigationcontroller?

Hello. Next problem. I programmatically add uinavigationcontroller as rootviewcontroller to my application. In it I hide the navigationBar using setNavigationBarHidden(true). Unfortunately, the swipe back gesture doesn't work. Stupidly does not respond to swipe. Tried everything on stackoverflow. I even used Libu - to no purpose. I don’t know where to look for a solution.
Router initialization code

private var window: UIWindow
    
    private var rootNavigationController: UINavigationController!
    
    init( _ window: UIWindow) {
        self.window = window
        self.initNavigation()
    }
    
    private func initNavigation() {
        rootNavigationController = UINavigationController()
        rootNavigationController.setNavigationBarHidden(true, animated: false)
        window.rootViewController = rootNavigationController
        window.makeKeyAndVisible()
        window.backgroundColor = .white
    }

Insert code for new viewcontroller:
private func goBackToViewController(_ navigation: UINavigationController, _ viewController: UIViewController) -> Bool {
        for controller in navigation.viewControllers {
            if controller.isKind(of: type(of: viewController)) {
                navigation.popToViewController(controller, animated: true)
                return true
            }
        }
        
        return false
    }

       private func showViewControllerByMethod(_ navigation: UINavigationController, _ viewController: UIViewController, _ method: ViewControllerShowMethod) {
        switch(method) {
        case .normal:
            navigation.pushViewController(viewController, animated: true)
        case .modal:
            navigation.present(viewController, animated: true)
        }
    }

     private func show(navigation: UINavigationController, _ viewController: UIViewController, method: PageShowMethod) {
        DispatchQueue.main.async {
            if(self.goBackToViewController(navigation, viewController)) {
                return
            }
            
            navigation.view.endEditing(true)
            
            self.showViewControllerByMethod(navigation, viewController, method)
        }
    }

Code for getting viewcontroller from any storyboard in the project
private func getController(storyboard storyboardName: String, controllerName: String? = nil) -> UIViewController? {
        
        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
        
        let controller = controllerName == nil ?
            storyboard.instantiateInitialViewController() :
            storyboard.instantiateViewController(withIdentifier: controllerName!)
        
        return controller
    }

And finally, the initialization code for the first rootviewcontroller in uinavigationcontroller:
func showFirstViewController() {
        var viewControllers = [UIViewController]()
        
        let firstTabController = getController(storyboard: "First") as! FirstViewController
        let firstTabNavigation = UINavigationController(rootViewController: firstTabController)
        firstTabNavigation.setNavigationBarHidden(true, animated: false)
        firstTabNavigation.tabBarItem = UITabBarItem(title: nil, image: UIImage(named: "home-icon"), selectedImage: UIImage(named: "home-filled-icon"))
        viewControllers.append(firstTabNavigation)
        
        let secondTabController = getController(storyboard: "Second") as! SecondViewController
        let secondTabNavigation = UINavigationController(rootViewController: secondTabController)
        secondTabNavigation.tabBarItem = UITabBarItem(title: nil, image: UIImage(named: "second-icon"), selectedImage: UIImage(named: "second-filled-icon"))
        viewControllers.append(secondTabNavigation)
        
        let tabBarController = BasicTabContainerViewController()
        tabBarController.viewControllers = viewControllers
        
        rootNavigationController.viewControllers.insert(tabBarController, at: 0) // Это на тот случай если у нас ранее были viewcontrollers и от них нужно уйти - к примеру контроллеры авторизации
        
        show(navigation: rootNavigationController, tabBarController, method: .normal) // А это чтобы с предыдущих контроллеров возвратиться с анимацией на этот
    }

I also have a special function for getting the current navigationController from the root tabbarcontroller
func basicContainerActiveNavigationController() -> UINavigationController? {
        var tabBarController: BasicTabContainerViewController? = nil
        for controller in rootNavigationController.viewControllers {
            if (controller.isKind(of: BasicContainerViewController.self)) {
                tabBarController = controller as? BasicContainerViewController
            }
        }
        
        return tabBarController?.selectedViewController as? UINavigationController
    }

This is all done this way because in my application, before the root tabarcontroller is displayed, the user is authorized and checked for this, and if the user is not authorized, the authorization window is shown again - that's why the rootnavigationcontroller exists, and for further transitions inside the tabbarcontroller I made a determination of the current active navigationcontroller
Next I change to a new controller
func showNewController() {
        let viewController = getController(storyboard: "New") as! NewViewController
        
        guard let navigationCotnroller = basicContainerActiveNavigationController() else {
            return
        }
        show(navigation: navigationCotnroller, viewController, method: .normal)
    }

In general, such a confused navigation

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dima Grib, 2019-07-02
@YeahGarage

navigationController?.interactivePopGestureRecognizer?.isEnabled = true
navigationController?.interactivePopGestureRecognizer?.delegate = nil

extension UINavigationController: UINavigationControllerDelegate {
    
    open override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }
    
    public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
        if responds(to: #selector(getter: self.interactivePopGestureRecognizer)) {
            if viewControllers.count > 1 {
                interactivePopGestureRecognizer?.isEnabled = true
            } else {
                interactivePopGestureRecognizer?.isEnabled = false
            }
        }
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question