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: {})
Related
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 an existing UITableViewController that I've embedded in a NavigationController. However, the Navigation Bar is not showing when I present the view.
Presenting the TableViewController (its Storyboard id is: SelectServicesController) :
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
This is what it looks like when I build (nav bar does not show):
So I just did this and at fist could not get it to show up at all. Then Figured it out, You just need to select the navigation controller and set it to be the ✅is initial View Controller
This is what your storyboard should look like
Then to make everything show up I added this to my viewDidLoad of the view the Navigation controller is presenting. This step is more optional.
self.navigationController?.navigationBar.barTintColor = UIColor.redColor()
self.navigationController?.navigationBar.tintColor = UIColor.blackColor()
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
navigationController?.navigationBar.hidden = false
And this is what it looks like
mmmm Red on black 🤓 Hope that helps you.
You're presenting a UITableViewController, which doesn't have a navigation controller as a parent (even though your Storyboard has it first, you're not actually using it).
You can fix this by doing something like this:
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
let navigationController = UINavigationController(rootViewController: selectServicesController)
self.navigationController?.presentViewController(navigationController, animated: true, completion: nil)
}
Or by setting the navigation controller as the initial view controller of the storyboard and then calling it like this:
if let selectServicesController = self.storyboard?.instantiateInitialViewController() {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
I encountered the same problem. I solved it by Changing the segue to the navigation controller that embeds the View Controller I want to display.
Hopefully it would work for you.
Let me know if it is a bad practice.
let storyboard = UIStoryboard(name: "Expense", bundle: Bundle(for: PTCAddExpenseViewController.self))
let controller = storyboard.instantiateViewController(withIdentifier:"AddExpense") as! PTCAddExpenseViewController
let navigationController = UINavigationController(rootViewController: controller)
self.present(navigationController, animated: true, completion: nil)
Adding this works for me:
self.navigationController?.isNavigationBarHidden = false
You're presenting the table view controller directly, not its navigation controller. If you mark the nav controller as the initial view controller (tick the "Is initial view controller" box in the attributes inspector), then you can instantiate and show it by:
if let selectServicesNavController = self.storyboard?.instantiateInitialViewController() as? UINavigationController {
// if you're pushing it onto an existing nav controller
self.navigationController?.presentViewController(selectServicesNavController, animated: true, completion: nil)
// if not (and this is probably the case), set the nav controller as your window's rootViewController
UIApplication.sharedApplication().keyWindow.rootViewController = selectServicesNavController
}
My guess is Xcode is ignoring the fact that your table view controller is embedded in navigation controller when presenting your table view controller with the following code:
if let selectServicesController = self.storyboard?.instantiateViewControllerWithIdentifier("SelectServicesController") as? UITableViewController {
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
}
Instead, I would suggest you modify the Top Bar setting under Simulated Metrics to suit your needs or instantiate your navigation controller instead (the latter is preferred and recommended)
In your code, change this line
self.navigationController?.presentViewController(selectServicesController, animated: true, completion: nil)
to this
self.presentViewController(selectServicesController, animated: true, completion: nil)
I read in one of your comments you want to present the table view controller modally, with the navigation bar showing. We can do this using the Storyboard. From the view controller that should display this table view controller modally, Ctrl+Drag from the view controller to the Navigation Controller of the Table View Controller. Then, select Present Modally. Set an Identifier for the segue. Then, in your code for the view controller that is presenting the table view controller modally, call:
self.performSegueWithIdentifier("YourSegueIdentifier", sender: nil)
Another way to do this without having to use any code is if the modal presentation is being triggered by something like a button. Then, you can Ctrl+Drag from that button to the Navigation Controller and select Present Modally.
Or it might be this!!
I had the same problem: the navigation bar was showing on the root view in Storyboard, but when running the Simulator - there was no navigation bar at the top of the views. This solved it:
Navigation Controller > Navigation Bar > UNCHECK Translucent (it is checked by default). This did two things:
My Navigation Bar shows on all subsequent views.
The topmost subview is now at Y=0, and not Y=64.
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...
I am working on a project that is a tabbed application. I have a button on my home page that goes to the second tabbed page but when it loads it gets rid of the tabs at the bottom.
How do I prevent this from happening? my code:
func manageButtonPressed() {
let NVC:SecondViewController = SecondViewController()
self.presentViewController(NVC, animated: true, completion: nil)
}
Replace:
self.presentViewController(NVC, animated: true, completion: nil)
With:
self.tabBarController?.selectedIndex = 1
This is assuming that your home page button is at index 0 on the first tab button of Tab bar, while second VC is on second tab at index 1. You may change the index based on the position of your tab bar.
You want to use showViewController method off of a uinavigationcontroller.
So in the main storyboard of the view where you call the presentViewController you need to add a UINavigationController. Then you can call in the view
self.navigationController.showViewController(NVC, sender: self)
Then it will add the view onto the top of the navigation stack and will be underneath the tab bar
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.