I have a navigation view controller, imagine this situation:
My views contollers: vc1, vc2, vc3, vc4
My root navigation controller: nc
And the stack of view controllers is like this:
nc > vc1 > vc2 > vc3
Now I am in vc3. I want to know how detect if you are going to a previous view controller (vc2) or you are moving to a new one (v4).
Guess this should be checked on viewWillDisappear method.
I am trying to check it with:
self.isMovingFromParentViewController()
But it only returns true if the previous vc is the navigation root.
Any further information you need just let me know, thanks.
EDIT:
Pushing
self.navigationController?.pushViewController(imageViewController, animated: true)
Going to previous view controller:
I am not using dismiss, just swipping or pushing back button of the navigation.
(Swift 2.3)
Well I have found this solution (same question) it's in objective-C but I translate it to Swift and I have made one more modifications. Since I don't do dismiss view controller then if you are not pushing view controller then you are going back.
if let viewControllers = self.navigationController?.viewControllers {
if viewControllers.count > 1 && viewControllers[viewControllers.count-2] == self {
print("New view controller was pushed")
}
else {
print("View controller was popped")
}
}
Thanks everyone!
If ViewDidLoad called, then you are pushing a new ViewController, else ViewController is already in the navigation controller stack and you are going to previous ViewController.
UPDATED
Things are trickier if you want to know when the navigation bar pops an item, you need navigationBar:shouldPopItem:
. Check this out for more information. If you want to do something before the pop
, the best way I can think of is to extend the UINavigationController
.
@objc public protocol NavigationBarDelegate {
@objc optional func navigationBarShouldPop() -> Bool }
extension UINavigationController: UINavigationBarDelegate {
public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
if viewControllers.count < (navigationBar.items?.count)! {
// When it's being called twice
return true
}
guard let vc = self.topViewController else { return true }
var shouldPop = true
if vc.responds(to: #selector(vc.navigationBarShouldPop)) {
shouldPop = vc.navigationBarShouldPop()
}
if shouldPop {
DispatchQueue.main.async {
self.popViewController(animated: true)
}
} else {
DispatchQueue.main.async {
// To fix the problem of back button disabled
let dimmed = navigationBar.subviews.flatMap {$0.alpha < 1 ? $0 : nil}
UIView.animate(withDuration: 0.25, animations: {
dimmed.forEach { $0.alpha = 1 }
})
}
}
return false
}
}
And then if you want to do anything before your view controller get popped
class VC3: UIViewController, NavigationBarDelegate {
func navigationBarShouldPop() -> Bool {
// Do whatever you want here
return true
}
}
ORIGINAL
Assuming that you are in vc3
and of course you use NavigationController
now. There should be 3 scenarios:
(1) You want to go back to vc2
dismiss(animated: true, completion: nil)
(2) You want to navigate to a new view controller (vc4
) and you use interface builder
let vc4 = VC4(nibName: "VC4View", bundle: nil)
navigationController?.pushViewController(vc4, animated: true)
(3) You want to pop to a view on stack but not the immediately previous one. E.g., vc1
// If the destination view controller is already on the stack, just pop to it
for item in (navigationController?.viewControllers)! {
if item.isKind(of: VC1.self) {
_ = navigationController?.popToViewController(item, animated: true)
}
}