Reputation: 559
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
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