Reputation: 781
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)
Upvotes: 2
Views: 4172
Reputation: 781
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!
Upvotes: 1
Reputation: 3499
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)
}
}
Upvotes: 1
Reputation: 931
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.
Upvotes: 0