Changing view controller to tab bar controller - ios

I have a tab based application with 2 tabs (HomeViewController and SettingsViewController).
On the SettingsViewController I have a button that will take the user to a third view (ChangeSomeSettingController).
On that third view, I have a TableView with this function
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
...
let settingsViewController = self.storyboard!.instantiateViewControllerWithIdentifier("SettingsViewController") as! SettingsViewController
self.presentViewController(settingsViewController, animated:true, completion:nil)
}
This will move the user back to the SettingsViewController. However, I am not able to get the tab bar to display at the bottom of the screen like it is when I first load the application.
How can I go back to the SettingsViewController and keep the tabs at the bottom of the screen?

First of all, presentViewController:animated:completion: will present SettingsViewController modally. What you need is a UINavigationController flow.
1) Add create UITabBarController
2) Select the item(UIViewController) that will has a UINavigationControler flow.
3) Delete it
4) Add UITableViewController
5) Add the new UITableViewController to the UITabBarController
6) Select the UITableViewController and embed in(Editor > Embed In > Navigation Controller) to a Navigation Controller.
7) Add a UIViewController and add a segue(Show) between UITableViewController and UIViewController
8) The result final result should be something like this:

In ChangeSomeSettingController, if you pushViewController from SettingViewController, you should call
navigationController?.popViewControllerAnimated(true)
or if you want to back to SettingViewController
//back to root view controller from navigation
navigationController?.popToRootViewControllerAnimated(true)
// you should call to tabbar view controller
UITabbarViewController *tabbarVC = (UITabbarViewController *)[UIApplication sharedApplication] delegate].window.rootViewController;
[tabBarController setSelectedIndex:1]; // 1 is index of SettingViewController
This's example for me, with your problem you can modify to adapt your requirement. hope this help for you.

This line:
self.presentViewController(settingsViewController, animated:true, completion:nil)
will not move back the user to settings VC, it will present a new instance of the settings VC, which ofcourse covers the tab bar.
You need to push the VC when you select the tabs, so you don't have to present them again if you want to go back.
If you don't want a navigation controller, then you should present the tab bar controller instead of settings vc.

Related

TabBar is hidden after going back to the initial ViewController of a TabBarController Using Segue

I have a tab bar controller with three table view controllers and the second VC is embedded in a navigation Controller. in the second VC, I made the tabBar hidden using this line self.tabBarController?.tabBar.isHidden = true and I created a bar button to go back to the first view controller which is the "home" VC using segue with modal presentation.
Screenshot of my StoryBoard
My problem is after hitting the back button and going back to home VC from the second VC, the tabBar is still hidden even though I put self.tabBarController?.tabBar.isHidden = false in the home VC's viewWillAppear method and the second VC's viewWillDisappear method.
Here is the result that I expected vs what I got
expected home VC
result home VC
How can I make the Tab Bar show?
When you are using the modal presentation segue, you are creating a completely new instance of HomeViewController. The new HomeViewController is not linked to the TabBarController in your hierarchy.
Here's you initial view hierarchy:
TabBarController
-> HomeVC
-> CreateVC (Navigation Controller)
-> CreateQuizVC
-> SavedVC
Now after tapping the back button you'll get the following:
TabBarController
-> HomeVC
-> CreateVC (Navigation Controller)
-> CreateQuizVC
-> HomeVC(2)
-> SavedVC
What you could do is, instead of using the segue to go back, add an IBAction in your code to set the selectedIndex of the TabBar programatically, and link the Back UIBarButtonItem to this IBAction.
#IBAction func backButtonAction(_ backButton: UIBarButtonItem) {
// Keep in mind that the CreateQuizVC is embeded in a NavigationController.
// The NavigationController is the child of the TabBarController
navigationController?.tabBarController?.selectedIndex = 0
navigationController?.tabBarController?.tabBar.isHidden = false
}
However, my suggestion is you use the TabBar as it's intended by Apple. Don't hide it while you're presenting your CreateQuizVC, and use the TabBar to navigate between the tabs. This will help with user experience, since everybody on iOS is expecting this behaviour from a TabBar.

Opening a navigation controller from Tabbar with back button on first ViewController

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

How to hide Tabbarcontroller's first view controller and go directly to the next controller but should show the tab bar items at the bottom

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.

How to handle a view controller independantly in UITabBarController?

My app's root is a UITabBarController with 5 sections, each of them contains a UINavigationController.
I also want to add a chat feature in the app, that could be accessed with a rightBarButton present in every navigation bar of the app. I would like it to show a chat UIViewController on the screen, unselecting the currently selected tab bar item and without losing the navigation state of the five navigation controllers, even the one that was previously selected before tapping the chat button. What would be my best bet to do it?
Thanks for your help/ideas.
Step 1: In your storyboard add a ChatViewController
- Embed your ChatViewController in Navigation View Controller if you wanna have a navigation bar. Add a close BarButtonItem in your ChatViewController.
Step 2: Create a close Action in your ChatViewController and binding with BarButtonItem in the StoryBoard.
#IBAction func CloseAction(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
Step 3:
In storyboard, select the Navigation Controllers with the rightBarButton and choose Present Modally and connect to Navigation Controller of the ChatViewController.
You can go to the ChatViewController without losing the navigation state of any navigation controller.

Instantiate View controller with its tab bar from unlinked viewcontroller

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.

Resources