Swift - How to remove a viewcontroller from NavigationController? - swift

I've got 4 ViewControllers attached to a NavigationController. The order of them is 1->2->3->4. When the user presses the back button on 4, I'd like them to be redirected to 2 instead of 3. At the same time, I'd also like the user to be directed back to 2 when the back button is pressed on 3. Is this possible? Thanks in advance.

Of course you can do this. Simply create the left bar button on 4th ViewController. and on that button action pop to 2nd viewcontroller
if let viewcontroller = self.navigationController?.viewControllers[1] where viewcontroller.isKindOfClass(YourController) {
self.navigationController?.popToViewController(viewcontroller, animated: false) }

if let vc = self.viewControllerWithClass(YourVC.self) {
self.popToViewController(vc, animated: true)
}
extension UINavigationController {
func viewControllerWithClass(_ aClass: AnyClass) -> UIViewController? {
for vc in self.viewControllers {
if vc.isMember(of: aClass) {
return vc
}
}
return nil
}
}

You can check for the controller in navigation stack.
let controllers = navigationController!.viewControllers.reverse()
for controller in controllers
{
if controller.isKindOfClass(YourController)
{
self.navigationController?.popToViewController(controller, animated: true)
return
}
}

Related

hidesBottomBarWhenPushed is not working when tabbarcontroller-viewcontroller's are embedded in navigation controller

My app ui heirarchy look like as shown. UItabbarcontroller -> navigation-controllers -> view-controllers.
The problem am facing is hidesBottomBarWhenPushed is not working when i try to push a new controller from 1st Vc on button click
if let newVc = UIStoryboard.homeSB.instantiateViewController(withIdentifier: NewViewController.identifier()) as? NewViewController{
self.navigationController?.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(viewAllVc, animated: true)
}
The Tabbar is still showing in the NewVc
//use this method in the view controller where you want to hide tabBar
override var hidesBottomBarWhenPushed: Bool {
get {
return navigationController?.topViewController == self
}
set {
super.hidesBottomBarWhenPushed = newValue
}
}
To hide the tab bar in new VC you can call this in viewDidLoad():
self.tabBarController?.tabBar.isHidden = true
Also, you should call method hidesBottomBarWhenPushed from your VC, not from the navigation controller:
if let newVc = UIStoryboard.homeSB.instantiateViewController(withIdentifier: NewViewController.identifier()) as? NewViewController{
newVc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(viewAllVc, animated: true)
}
Furthermore, you can make it on your new VC storyboard:
hidesBottomBarWhenPushed in developer.apple.com/documentation

Dismiss viewcontroller depends on presentation style (modal or push)

I did FoodTracker programmatically and here is the code that doesn't work for me.
func cancel(){
let isPresentingInAddMealMode = presentingViewController is UINavigationController
if isPresentingInAddMealMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController {
owningNavigationController.popViewController(animated: true)
}
else {
fatalError("The MealViewController is not inside a navigation controller.")
}
}
Here is how it looks in the storyboard:
Actually it works modally when the plus button is pressed but it doesn't work with popviewcontroller. I pushed it in the navigation stack with didSelectRow in tableViewController.

How to dismiss controller and then switch tabs

I have two main VC that are in a tab bar controller. On the first VC when you tap a button you are taken to another VC (not the 2nd tab bar VC) and when you tap the finish button I want to go to the 2nd tab bar vc.
Normally I would just perform segue ... but when I do that it removes the tab bar at the bottom. So, I am now just dismissing and going back to the original VC, but I would really like to go to the 2nd tab bar vc so I tried this
dismiss(animated: true) {
self.tabBarController?.selectedIndex = 2
}
I saw the self.tabBar... on another SO post, but I can't seem to find where I set the Index...ive tried 1 in case it just automatically starts from 0, and Ive tried 2 in case it starts from 1
Am I close or is there a better way of achieving what I want?
Summary
To summarize clearly. I have 3 View Controllers. 1 and 3 are in a Tab Bar Controller. VC 2 is NOT in the TBC. To get to VC 2 there is a button on VC 1. When the user is finished on VC 2 he/she taps a button. Instead of just dismissing back to VC 1 I want to go to VC 3, but when I perform segue it goes to VC 3 but removes the Tab Bar
Make sure you have a UINavigationController as the first ViewController. Then you have access to the tabBarController and can then switch the tabs:
// if vc was pushed
#IBAction func onFinish(_ sender: Any) {
// store tabBarController for later use
let tabBarController = self.tabBarController
// pop to root vc (green one)
_ = self.navigationController?.popToRootViewController(animated: false)
// switch to 2nd tab (red vc)
tabBarController?.selectedIndex = 1
}
// if vc was presented modally
#IBAction func onFinish(_ sender: Any) {
self.dismiss(animated: false, completion: nil)
if let tabBarController = self.presentingViewController as? UITabBarController {
tabBarController.selectedIndex = 1
}
}
// if vc was presented modally + switching tab in completion block
#IBAction func onFinish(_ sender: Any) {
if let tabBarController = self.presentingViewController as? UITabBarController {
self.dismiss(animated: true) {
tabBarController.selectedIndex = 1
}
}
}
Indexes will most likely always start from 0 in any language you use.
As for the tab bar you are calling self on the view controller presented not on the view controller that it is dismissing to. You should be able to do
self.window?.rootViewController.tabBarController?.selectedIndex = 1
in order to accomplish this. This might not work based on the setup of your VCs so you might have to play with it.
You can move to specific index before dismiss view controller.
func moveToVC() {
if let mainNavVC = self.presentingViewController as? UINavigationController {
if mainNavVC.viewControllers.count > 0 {
if let tabbarVC = mainNavVC.viewControllers.first as? TabBarViewController {
tabbarVC.selectedIndex = 0
}
}
}
}

How to click a button programmatically?

I have 2 view controllers which should be swapped according to userinput. So, I want to switch the views programatically based on the input I get from a text file.
Algorithm :
if(input == 1)
{
Go to View Controller 1
}
else if(input ==2)
{
Go to View Controller 2
}
Any help on how to click the button programmatically or load that particular viewcontroller with input?
To fire an event programmatically you need to call sendActionsForControlEvent
button.sendActionsForControlEvents(.TouchUpInside)
--
Swift 3
button.sendActions(for: .touchUpInside)
Or you can just put all the logic that you perform when a button gets clicked in a separate method, and call that method from your button's selector method.
#IBAction func someButtonPressed(button: UIButton) {
pushViewControllerOne()
}
#IBAction func someButtonPressed(button: UIButton) {
pushViewControllerTwo()
}
func pushViewControllerOne() {
let viewController = ViewControllerOne(nibName: "ViewControllerOne", bundle: nil)
pushViewController(viewController)
}
func pushViewControllerTwo() {
let viewController = ViewControllerOne(nibName: "ViewControllerTwo", bundle: nil)
pushViewController(viewController)
}
func pushViewController(viewController: UIViewController) {
navigationController?.pushViewController(viewController, animated: true)
}
Then instead of invoking programatically invoking a button press, just call the method pushViewControllerOne() or pushViewControllerTwo()

Back when current view controller is not presented by segue. Swift

I am trying to present VC2 from VC1 without using segue. It works. Then, I tried to use self.navigationController?.popViewControllerAnimated(true) to back but it does not work. I am wondering what is the code I should use to back from VC2 to VC1. Below code is in appDelegate.
AppDelegate
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let VC2 = storyboard.instantiateViewControllerWithIdentifier("VC2") as! VC2
let navController = UINavigationController(rootViewController: VC2)
self.topViewController()!.presentViewController(navController, animated: false, completion: nil)
func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let MMDrawers = base as? MMDrawerController {
for MMDrawer in MMDrawers.childViewControllers {
return topViewController(MMDrawer)
}
}
if let nav = base as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(presented)
}
return base
}
VC2
#IBAction func backButtonTapped(sender: AnyObject) {
print(self.navigationController?.viewControllers) // print([<MyAppName.VC2: 0x12f147200>])
self.navigationController?.popViewControllerAnimated(true)
}
Here is the Flow of your navigation :
Current Screen - Presenting A New Screen (Which itself embed within a navigation controller with vc2) so Popviewcontroller won't work .
If you present any viewcontroller then popviewcontroller wont work rather use dismissviewcontroller to come out previous screen .
Use This :
self.dismissViewControllerAnimated(true, completion: {})
Solved!
Thanks.