This question already has an answer here:
self.tabBarController dismissViewControllerAnimated doesn't work
(1 answer)
Closed 6 years ago.
I'm having a hard time presenting a tab bar controller that is not the root view controller.
I have the current setup:
I want to press a button in my main view controller and be able to present the tab bar controller with the option to go back to the main view controller.
I tried creating a class of type UITabBarViewController, associating it to my Tab Bar Controller and just presenting it but it does not work.
I would like to present the tab bar controller with the favorites tab selected.
What I tried:
let vc = TabBar()
self.presentViewController(vc, animated: true, completion: nil)
You can switch tabs by setting a selected index property of UITabBarController. Like this:
tabBarController.selectedIndex = 1
You don't need to create new view controllers or perform segues if all you want is to switch between the two tabs.
You can do it in tow manner :
using segue :
Drag from button to the tabBarViewController And choose a type (Modal, Push(if your mainViewController is NavBarVC) ...)
from code :
click on your tabBarViewController and go to the attributes inspector and give your VC a storyboard id
and from code :
let mainST = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let VC = mainST.instantiateViewControllerWithIdentifier("idTabBar")
presentViewController(VC, animated: true, completion: nil)
Edit dismiss tabBar
if the tabBar is presented modally,
to dismiss it you have tow choices :
1) using a delegate :
protocol ExitMe {
func exitMe()
}
In the view controller presenter of the tabBar
extension PresenterOfTabBar: ExitMe{
func exitMe(){
dismissViewControllerAnimated(false, completion: nil)
}
}
and in the tabBarViewController define an exitDelegate variable var exitDelegate: ExitMe! and set it's value from the presenter. When the user click a button to exit tabBar you just call exitDelegate.exitMe()
using an unwindFuction when presenting modally using a segue:
in the presenter you define a function like this
#IBAction func unwindFromTabBar(sender: UIStoryboardSegue){
// do what you want here
}
and in the InterfaceBuilder drag from the the button that should exit the tabbar to the exit in the view controller dock then choose the func unwindFromTabBar.
Others solutions may exist (using notification, get the prsenter View controllers ....) you should pick the suitable one...
Related
I currently have parental "menu" TableView with UINavigationBar and from each cell there is a segues by reference outlet to 3 similar Views with different information.
In each View there is a buttons to other 2 Views.
With every button's segue opens another View.
The problem:
From every View UINavigationBar's back button returns me to previous View but i tries to make back button to "menu".
Additional Bar Button Item and segue from it makes very close effect but segue animation is not like in UINavigationController.
How I could clean UINavigationBar transitions history in segue to initial View?
You can try pop to root view controller or You can edit navigation controller viewControllers property and remove/add some VC in between.
You can try Unwind Segue mechanism too.
Here are some methods(function) that navigation controller providing for pop operations. They are returning optional UIViewController (intance) from it’s navigation stack, that is popped.
open func popViewController(animated: Bool) -> UIViewController? // Returns the popped controller.
open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? // Pops view controllers until the one specified is on top. Returns the popped controllers.
open func popToRootViewController(animated: Bool) -> [UIViewController]?
Here is sample code as a solution to your query::
// if you want to back to root of your app
if let rootNavigationController = self.window?.rootViewController as? UINavigationController {
rootNavigationController.popToRootViewControllerAnimated(true)
}
// But if you want to back to root of your current navigation
if let viewcontroller = self.storyboard?.instantiateViewController(withIdentifier: "NewViewController") as? NewViewController { // or instantiate view controller using any other method
viewcontroller.navigationController?.popToRootViewControllerAnimated(true)
}
I have two view controllers, I added navigation bar to second view controller with two bar button items Back and Item as shown below
But when I do a push segue from first view controller, it is replaced by navigation item <Category, which is title of navigation item in my first view controller as shown below
How do I keep my navigation bar intact avoiding the default navigation item <Category, which is being added automatically while maintaining push segue functionality.
I tried to do maually without using stoyboard as follows
#IBAction func plusAction(_ sender: Any) {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SVC") as? SecondViewController
self.navigationController?.pushViewController(secondViewController!, animated: true)
}
but it still doesnt work.
You want to display two bar button items Back and Item by added UINavigationBar to second view controller, you are doing it in the wrong way!!!
In your storyboard, drag a UINavigationItem to your second ViewController.
If the UINavigationItem does not display on your storyboard, you must select second view controller, choose Opaque Navigation Bar or Translucent Navigation Bar (not important)
After that, you can drag UIBarButtonItem where you want on your ViewController
Have you tried changing the kind of segue through segue inspector (click the particular segue and check its attributes in the inspector) like this,
But you should know each one of it is not similar, has it's own definition in how it appears - check https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html
Also, alternatively using code,
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "storyboardId") as? TargetViewController {
self.present(viewController, animated: false, completion: nil)
}
I have created a simple tab bar with three views in storyboard. The tab bar works well, but when I try to show another view controller from a button within a tab, the new view is placed over the whole screen and also over the tab bar.
This is how I present the view so far when a button is pressed:
#IBAction func buttonPressed(_ sender: UIButton) {
let newVC = self.storyboard?.instantiateViewController(withIdentifier: "extraVC")
self.present(newVC!, animated: true, completion: nil)
}
The other idea I had was this:
self.tabBarController?.present(vc!, animated: true, completion: nil)
But this didn't work either.
So how can I present another view controller within the tab bar (so that the bottom bar is still shown)?
When you present a view controller modally, its presentation style will be "Full Screen" by default. What you want to do is have it do in this case is just cover part of the screen (the part where the presenting view controller is drawn.
One way to accomplish this is to:
Set the modalPresentationStyle for the presented view controller to be .currentContext or .overCurrentContext
In the view controller that will be presenting the modal, set its definesContext property to true.
These steps can be done either in Interface Builder by setting attributes on the segue and the view controller, or you can modify your code to include the following:
#IBAction func buttonPressed(_ sender: UIButton) {
let newVC = self.storyboard?.instantiateViewController(withIdentifier: "extraVC")
self.definesPresentationContext = true
newVC?.modalPresentationStyle = .overCurrentContext
self.present(newVC!, animated: true, completion: nil)
}
What this combination of properties does is:
Indicate for the presented view controller that you want it to be presented in a non-full screen context (some specific section of the screen)
Indicate that the presenting view controller is in the section of the screen / the context you want the modal to be drawn according to.
More details can be found in the Apple Documentation
When you are using present method, the ViewController is presented modally and covers your UITabBarConntroller. Instead of showing your view modally you can embed every first view controller in your TabBar into UINavigationController and then use method pushViewController to push it onto stack. You will have your TabBar visible and nice looking animation for free.
In Xcode, I created a new project using the Tabbed App template to illustrate the solution above. This will create a project with a tabbar controller and two view controllers. I added a button with the title "view page" to the first view controller and embedded a navigation controller from the storyboard.
The storyboard will look like this after making the above changes:
In the FirstViewController.swift file, I created an IBAction for the button with the following code that will create another view controller called DetailViewController, with the title Favorites and a background color of orange. I used the navigation controller to present it by pushing it onto the navigation controller stack.
#IBAction func viewPageButtonTapped(_ sender: UIButton) {
print("viewPageButtonTapped")
let pinkViewController = DetailViewController()
pinkViewController.title = "Favorites"
pinkViewController.view.backgroundColor = UIColor.orange
navigationController?.pushViewController(pinkViewController, animated: true)
}
When I run the project on the simulator, I got the desired result. Hope this helps give you some ideas.
In your viewController do:
self.tabBarController?.present(nextViewController, animated: true/false, completion: {})
I am trying to display a fix navigation bar for my UiTableViewController, I have a first ViewController and when I click on it, this will open my UITableViewController Here is the code of the click :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MyTableViewController") as! MyTableViewController
vc.myObject = object // I pass some data
presentViewController(vc, animated: true, completion: nil)
the UItableView is correctly display but not navigation bar appear, if I add one, the navigation bar scroll with the table view and I don't want this behavior.
I tried this without success :
Go to the Editor menu, and click on the Embed In submenu, and choose
Navigation Controller
And tried to change some settings here :
Actually, in your case you want to show navigation and for navigation you have to push your view controller to a UINavigationController thats why the solution is :
let vc = storyboard.instantiateViewControllerWithIdentifier("MyTableViewController") as! MyTableViewController
vc.myObject = object // I pass some data
self.navigationController?.pushViewController(vc, animated: true)
presentViewController offers a mechanism to display a modal view controller; i.e., a view controller that will take full control of your UI by being superimposed on top of a parent controller & establish a parent child relation b/w presenting & presented view controllers.
where as
pushViewController offers a much more flexible navigation process where you can push & pop a new controller to UINavigationController, so to go back to the previous one, in a ordered way. Imagine that controllers in a navigation controller will just build a sequence from left to right like building a stack of view controllers stacking upon each other.
Do it this way:
let vc = storyboard.instantiateViewControllerWithIdentifier("MyTableViewController") as! MyTableViewController
vc.myObject = object // I pass some data
self.navigationController?.pushViewController(vc, animated: true)
I'm new to swift and IOS development. I'm working on a tabbed application(3 views). For example, FirstView, SecondView and ThirdView. FirstView has a button that opens a addNewSession view and the addNewSession view has a Back button that back to the FirstView. The problem is Tab bar disappears after back from the addNewSession view
FirstView to addNewSession view.
#IBAction func toAddNew(sender: AnyObject) {
let addNewSession = self.storyboard?.instantiateViewControllerWithIdentifier("addNewSession") as addNew
self.presentViewController(addNewSession, animated: true, completion: nil)
}
addNewSession view to FirstView
#IBAction func backToPrev(sender: AnyObject) {
println("test1")
let FirstView = self.storyboard?.instantiateViewControllerWithIdentifier("FirstView") as FirstViewController
self.presentViewController(FirstView, animated: true, completion: nil)
}
The problem is your backToPrev method is instantiating a new FirstViewController, which is not the same instance you came from. You are not really going back to the original one, you are showing a new one. This is not what you want.
The proper way to do this is to embed the FirstViewController in a navigation controller, then push the addNew controller onto it. When you use a nav controller, you get the Back behavior for free.
Hopefully you are using a storyboard? Select your FirstViewController, go to the Editor menu and choose Embed in Navigation Controller.
In your toAddNew, instead of presentViewController use self.navigationController.pushViewController to push your addNew controller.
There's an even easier way to do this last step, using segues. You control drag in the storyboard from your button in FirstViewController to the addNew controller and create a Show segue. This will automatically show your addNew controller when the button is touched. With this approach, you will want to remove your toAddNew IBAction and the connection since it's redundant.