I have a viewController related to a Tab Bar Controller: the first one.
Clicking on a cell of its tableview, I'll show programmatically another viewController that's not linked to the first viewController with no segue (because of right reasons).
Now, my goal is to present/instantiate the second viewController related to the tab bar mentioned at the beginning of this question.
If I'll use this:
let vc=storyboard?.instantiateViewController(withIdentifier: "offerteView") as! SecondViewController
It'll be presented the mentioned viewController without the tab bar of course.
How can I solve it?
Embed the first view controller in a navigation controller and use its pushViewController function to show the second view controller.
let vc = storyboard?.instantiateViewController(withIdentifier: "offerteView") as! SecondViewController
navigationController?.pushViewController(vc, animated: true)
when using tab bars the view controllers are called on the basis of their Index and because of this the tab bars are still maintained and this can be done like this.
self.tabBarController!.selectedViewController! = self.tabBarController!.viewControllers[3]
where [3] is the index position of the View Controller.
or
self.tabBarController.selectedIndex = 1;
//Hope it was helpful. Happy Coding.
Related
I know this question has been asked so many times on the SO, but I am asking this just because it is relevantly different and also some answers are out dated and some are in Objective-c which I can not understand properly.
USE CASE:
I have a UITabBar controller, and it is working fine. Let say I have 4 tabs in it and user click on the button given in the Tab 4. now on it I have to open some series of View Controllers. let say User has following patteren to follow.
4.A-->4.B--> 4.C and can go back to first like so: 4.C-->4.B-->4.A
And finally User must also be allowed to go back to Tab4 after closing 4.A view controller
WHAT I DID:
I am able to open the View controller using this code.
let VC1 = storyboard.instantiateViewController(withIdentifier :"myVcId") as! UIViewController
let navController = UINavigationController(rootViewController: VC1) // Creating a navigation controller with VC1 at the root of the navigation stack.
self.present(navController, animated:true, completion: nil)
This is opening a navigation controller and having me navigate the view controller as per my requirements but I want following thing too
WHAT I WANT: As I am presenting the Navigation Controller modally, I want to show the back button at very first view controller, and I want that if user select back button it kills all the Navigation controller and go the previous view controller where he came from
You need to select the 4th tab and embed it inside a navigation then do
let vc = storyboard.instantiateViewController(withIdentifier :"myVcId") as! UIViewController
self.navigationController?.pushViewController(vc, animated: true)
then you'll see a back on that first vc , to return to that tab do
self.navigationController?.popToRootViewController(animated: true)
As far as I understood, your structure looks like this:
A TabBarController, with ViewControllers as tabs, and from them you present a navigation controller with other ViewControllers, like this:
(TabBar) -vc-> (View) -present-> (NavController) -root-vc-> (View)
I have two suggestions for making it easier to handle.
First option
Use navigation controllers as tabs for your TabBarController, and make your ViewControllers that are tabs their root view controllers.
(TabBar) -vc-> (NavController) -root-vc-> (View) -push-> (View)
Second option
Another option is to use a navigation controller as your initial view controller, and make your tab bar this navigation controller's root view controller.
(NavController) -root-vc-> (TabBar) -view-> (View) -push-> (View)
Both options should work, and the first one should be a little easier to handle.
You need to instantiate the navigationController with 4A as the rootViewController.
Then, in the viewDidLoad for 4A, you need to instantiate 4B, and push it to your navigationController.
Then, finally, in your 4B viewController's viewDidLoad you need to instantiate 4C and push it to your navigationController's stack.
P.S.: Push all the viewControllers without animations.
This should be achieving your strange scenario.
EDITED:
You need your 4th tab from your tabBar to be a navigationController,
and its root view Controller to be the initial VC which will then push
your new navController, otherwise you won't have the back button.
So, your stack should be something like this:
4CVC
|-(push)
4BVC
|-(push)
4AVC
|-(push)
newNavController
|-(push)
someVC
|
navController
|
tab1 tab2 tab3 tab4
|
tabBar
I have a view controller as my initial view controller. there's a button in it(GO button) which when the user taps, it should go to another view controller(let's call it Destination view controller with label 'This is where i wanna go'). Meanwhile i want to pass it through a Tabbar controller. The reason is i want to have tabbar in my navigation stack.
I wish to go directly to the Destination view controller while pressing go button but it should show the tab bar items at the bottom.
So for achieving this in FirstViewController didLoadMethod I checked a bool value and pushed the view controller to the Destination view controller. I achieved the result I.e when pressing the Go button it goes to the Destination view controller and has tab bar items at it's bottom.
But the problem since it passes through the Tabbarcontroller the FirstViewController is shown for some seconds and then it pushes to the Destination view controller. I wish to hide FirstViewController while this transition takes place.
How to achieve this?
Picture shows what i want. what can I do to hide firstviewcontroller while having it in navigation stack?
I think this can be done in a simple way -
In the first viewController of the tab bar has a viewDidLoad() function or you can use loadView() which is called before the viewDidLoad() function. Push to the next viewController in the function.
Put your push navigation code in one of those functions
*You cant see the current view coltroller, it will push the screen to your required viewcontroller before loading the tab bar initial view contoller.
Hope it will work for you.
or >>>> you can check it out
let storyboard = UIStoryboard(name: "your_storyBoard_name", bundle: nil)
let viewController1 = storyboard.instantiateViewController(withIdentifier: "firstViewController")
let viewController2 = storyboard.instantiateViewController(withIdentifier: "secondViewcontroller")
let controllers = [viewController1, viewController2]
self.navigationController!.setViewControllers(self.navigationController!.viewControllers + controllers, animated: true)
The effect you're trying to produce is hard to do in a storyboard. Programmatically you would simply create the Tabbar Controller (with its children) and the "This is where I want to go" Controller, and then ask the navigation controller to show both at the same time.
For example, after "Go" is tapped, this is the code I would run inside your first view controller:
let tabBarController = UITabBarController()
let finalDestination = UIViewController()
var viewControllers = self.navigationController?.viewControllers ?? []
viewControllers.append(tabBarController)
viewControllers.append(finalDestination)
self.navigationController?.setViewControllers(viewControllers, animated: true)
Given the structure you shown, where the view controller A is the root view controller of the TabBar, you should push the second view controller B on the navigation stack inside either willAppear or didLoad of view controller A, according to your personal business logic (flag, conditions, etc.).
The trick here is to use either pushViewController or setViewControllers with animated: false so that the navigation stack will be set immediately during willAppear/didLoad and it won't show the push animation of B over A. This way, at onDidAppear the layout will be already fully rendered in it's final state: with B at the top of the navigation stack and no animations in progress.
As you can see below, the notificationsVC is a part of the TabBarController which is embedded in a navigationContoller(lets call it first nC). Then theres a segue from notificationsVC to the second navigationController which will show the messagesVC.
There's a back button in messagesVC which when pressed should go back to notificationsVC
func backbutton() {
navigationController?.popViewControllerAnimated(true)
}
Now this is obviously not working because the navigationController will get the nearest NC and pop the VC in its stack but it won't let me go back to the notificationsVC.
Any other alternative?, although I've tried this with no success as well.
self.dismissViewControllerAnimated(true, completion: nil);
More detailed view
Also I'm using the JSQMessagesViewController library to show the messages in messagesVC which shouldn't matter but still worth mentioning. Thanks for your time!
You can access first NavigationViewController by asking it from TabBarViewController like in code below:
tabBarController?.navigationController?.popViewControllerAnimated(true)
Also asking navigation controller from you second navigation controller should work:
navigationController?.navigationController?.popViewControllerAnimated(true)
Your Navigation controller has only one VC i.e MessagesVc. So when you pop it,there is no other VC in the Navigation Controller's stack which can be presented. Your NotificationsVC is not in the Navigation controller's stack.
So I suggest you to do like this on back button click:
tabBarController?.selectedIndex = Index_Of_NotificationsVC
Try : -
let nVC = self.navigationController?.tabBarController?.navigationController?.storyboard?.instantiateViewControllerWithIdentifier("NotificationStoryboardVC_ID") as! NotificationVC
navigationController?.tabBarController?.navigationController?.pushViewController(nVC, animated: true)
I had to add a navigation controller to my app so that I could use the left drawer menu (using SWRevealViewController) but its messing up my segues. My initial design had a login screen that segued to one of 4 different scenes depending on an a status indicator.
Now that I had to add a navigation controller it looks like i'll have to take the user sequentially through through each screen in the stack until they reach the relevant one. Is there a way I can jump past the first screen or 2? Or a way to not show them as I navigate through.
I tried putting the performSegue in the viewWillLoad delegate method but the screen still loads before segueing to the next scene.
Add Storyboard IDs to all View/Navigation Controllers that will eventually be pushed:
Now to push the desired view it depends whether your current View Controller stands: within or outside the Navigation Controller's stack:
If your VC is already in the Navigation Controller stack
From your current ViewController push the desired view:
if let myViewController = self.storyboard?.instantiateViewControllerWithIdentifier("myViewController") as? MyViewControllerClassName {
self.navigationController?.pushViewController(myViewController, animated: true)
}
Note: as? MyViewControllerClassName is only required if your View Controller's class is not the default UIViewController but a custom one that extends it instead.
If your VC is NOT in the Navigation Controller stack
Same principle apply, only this time you need to push the Navigation Controller itself before pushing the desired View Controller:
if let newNavController = self.storyboard?.instantiateViewControllerWithIdentifier("myNavigationController") as? UINavigationController {
self.view.window?.rootViewController = newNavController
// Now push the desired VC as the example above, only this time your reference to your nav controller is different
if let myViewController = self.storyboard?.instantiateViewControllerWithIdentifier("myViewController") as? MyViewControllerClassName {
newNavController.pushViewController(myViewController, animated: true)
}
}
I would like to know what code is required to traverse the storyboard from a UIViewController located at index N of a UINavigationController which is embedded in a UITabBarController, to a similarly embedded UIViewController.
I would also like all UIViewControllers to be popped in the source UINavigationController
Direct segues (as shown in red) do not fit my use case.
Swift please.
You can pop to the root view controller then change the selected index of the index of the tab bar controller then push whatever view controllers you need on the other navigation controller. For example:
let tabBarController = self.tabBarController;
let indexZeroNavController:UINavigationController = self.tabBarController?.viewControllers![0] as! UINavigationController
self.navigationController?.popToRootViewControllerAnimated(true)
tabBarController?.selectedIndex = 0
let newViewController = self.storyboard?.instantiateViewControllerWithIdentifier("New View Controller")
let otherNewViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Other New View Controller")
indexZeroNavController.pushViewController(newViewController!, animated: true)
indexZeroNavController.pushViewController(otherNewViewController!, animated: true)
Beyowulf's approach used to be valid, but things have changed. In the viewController you wish to pop to, define an "unwind segue". example Once it's defined, you can drag from a button to "exit" and select that unwind segue.
The way unwind segues work has been completely reworked in xcode 7, so you don't have to worry too much about the view controller stack.