A. Claesson
A. Claesson

Reputation: 559

UINavigationControllerDelegate methods are not called

I'm trying to make custom transitions when pushing/popping viewControllers from a custom UINavigationController class. I'm implementing the UINavigationControllerDelegate method navigationController(_:animationControllerFor:from:to:), but it does not get called.

I'm creating a UINavigationController in storyboard and putting it's class as CustomNavigationController. I'm also assigning it a root ViewController in the storyboard (let's call the root VC CustomViewControllerRoot).

Here is the code I'm using (simplified and not tested):


protocol NavigationDelegate {
 func pushCustomViewController()
 func popViewController()
}

class CustomNavigationController: UINavigationController, NavigationDelegate {

    init() {
      super.init(nibName: nil, bundle: nil)
      delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
      self.navigationBar.isHidden = true

      guard viewControllers.first is CustomViewControllerRoot else {fatalError("Error")}
      rootVC = viewControllers.first as? CustomViewControllerRoot
      rootVC?.navigationDelegate = self

      //Setup the rest of the viewControllers that are to be used
      customVC = CustomUIViewController()
      customVC?.navigationDelegate = self
    }

    var rootVC: CustomViewControllerRoot?
    var customVC: CustomViewController?    

    func pushCustomViewController() {
      if customVC != nil {
         self.pushViewController(customVC!, animated: true)
      }
    }

    func popViewController() {
      self.popViewController(animated: true)
    }
}


extension CustomNavigationController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        // This is never called, even though the delegate is set in the initializer to CustomNavigationController
        print("TEST")
        return nil
    }

}

I then let each custom UIViewController subclass in my navigation hierarchy delegate push or pops to this CustomNavigationController above. For example this is the root vc assigned to the navigation controller. Since it lies as root it never needs to push itself or be popped, as it is presented when the CustomNavigationController is presented. It delegates to CustomNavigationController when it finds that another VC should be presented on top of it:

class CustomViewControllerRoot {

 var navigationDelegate: NavigationDelegate?

 override func viewDidLoad(){
   super.viewDidLoad()
 }

 @objc func someButtonPressedToPresentCustomVC(){
   navigationDelegate?.pushCustomViewController()
 }

}

The dismissal is handled inside each CustomViewController which also delegates the pop down to the CustomNavigationController (I don't want to use the navbar for dismissal so there is no "back button" from the start):

class CustomViewController: UIViewController {

 var navigationDelegate: NavigationDelegate?

 override func viewDidLoad(){
   super.viewDidLoad()
 }

 @objc func dismissViewController(){
   navigationDelegate?.popViewController()
 }  
}

To my understanding the UINavigationControllerDelegate method inside the extension of CustomNavigationController should be called whenever a push or pop is performed since I'm setting the delegate variable to self in the initializer?

Upvotes: 3

Views: 4883

Answers (1)

Zakhar
Zakhar

Reputation: 59

Your navigation controller should have a root view controller. And then you should push custom view controller from your root view controller. And delegate method calls

Navigation Controller Code:import UIKit

class CustomNV: UINavigationController {
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
    }
}

extension CustomNV: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        print("TEST")
        return nil
    }
}

RootViewController code:

class RootViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let viewController = UIViewController(nibName: nil, bundle: nil)
        viewController.view.backgroundColor = .green
        navigationController?.pushViewController(viewController, animated: true)
    }

}

Set root view controller as root for navigation controller in storyboard

Upvotes: 2

Related Questions