So I have a custom bottom tab bar that works if I add it as a subView to any of my views, but I would love for it to be part of the UINavigationController so I don't need to keep track of it in every view initialization. Is there a way to do this?
I can't add it as a subView of navigationBar because I think it is out of the frame and the touches don't register on the tab bar.
I can't subclass the navigationController because apple doesn't let you. So how do I get this working?
It's not true that Apple won't let you subclass a UINavigationController. As of iOS 6, it is allowed, however, I don't think that would help you anyway. I think the best way to do this is with a custom container controller. If you start with a UIViewController in IB, you can put your custom tab bar at the bottom (or just leave space for it and add it in code), and add a container view that fills the rest of the space. You can delete the default controller you get with that container view, and replace it with a navigation controller. As you navigate through your content controllers, your tab bar will remain in place.
Related
If I have the storyboard in the form of (where the arrows are segues)
UINavigationController -> ViewControllerA -> ViewControllerB
Would that be basically more or less equivalent to
ViewControllerA -> ViewControllerB
(NavigationBar) (NavigationBar)
if I manually wire each NavigationBar up to Button Bar Items with event listeners attached to unwind segues?
Or does UINavigationController offer something more than that?
UINavigationController is what is known as a container view-controller: it takes a bunch of other view-controllers and manages how their views are presented on the screen. UISplitViewController is another example of a container view-controller.
In the case of UINC, it:
Allows pushing a new "top" controller, animating it with a left-to-right/right-to-left animation depending on locale
Remembers the stack of previous top controllers, allowing you to pop back to them
Adds a UINavigationBar view above the top controller's view so the user can pop back by themselves (you can disable this)
Sets a layoutMargin on the top controller's view, so it can adjust content to not underlap the bar
Provides an edge-swipe gesture so the user can interactively pop to previous controllers (slowly peel the top sheet back)
For more information, including about how to create your own container view-controllers, see Apple's documentation on the subject: https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
There are some differences.
One that I have noticed, a UINavigationController will handle correctly putting the navigation bar in the right place for iPhone X vs other models (It will make the height larger so it goes into the wedge of the of screen, while just a nav bar will remain its standard height).
If you just put a nav bar on each UIViewController, you are going to have to check on each view controller if you need to update the bar size.
Basically the navigationController provides you many thing that you might use: A stack of UIViewControllers, a navigation bar, a toolbar, delegate methods, show/pop animations, etc. Doing all that by hand will be not too appropriate and a little bit messy. I suggest you to take a look to the Appleās documentation for UINavigationController. There you will get a much better understanding of all the capabilities and methods that this class provides you.
I'm trying to create a tabbed application with navigation elements inside the tab bar, as seen in the picture below (the red bar) using Swift/XCode 6.2. Basically those three icons in the middle will direct the user to different view controllers. The other two icons would be context-based. For example, on a table view page you would see the menu icon and add new icon as seen in the image. However, clicking on a row would change the menu icon to a back icon, and the add icon to something else.
That's the general idea, but I'm having a very hard time implementing something even close to this. The first issue is that whenever I embed a view in a Tab Bar Controller, I can't move the tab bar to the top. However, when I create a custom UITabView in a View Controller, Control + Click and dragging a Tab Bar Item to another view doesn't create a segue. I haven't even begun to tackle having the navigation elements inside the bar.
I guess what I'm asking is just for a little guidance on what route to take to tackle this. I'm assuming I can't use a Tab Bar Controller or Navigation Controller because it doesn't seem like I can customize them all that much. So custom Tab Bar and Navigation Bars, and then implemnt the segues and button changes programmatically?
Thanks.
I will try to guide you from an architectural perspective (so you won't find much code below).
Using a UITabBarController
In order to achieve what you are suggesting, you are right you cannot use a UITabBarController straight away, among several reasons, the most immediate one is that they are meant to be always at the bottom and you want it in top (check Apple's docs). The good news is that probably you don't need it!
Note: If you still want to go with a UITabBarController for whatever reason, please see #Matt's answer.
Using a UINavigationController
You can use a UINavigationController to solve this task, since the UINavigationBar of a UINavigationController can be customized. There are multiple ways on how you can organize your view's hierarchy to achieve what you propose, but let me elaborate one option:
To customize a UINavigationBar's to add buttons, you just need to set its navigationItem's title view:
// Assuming viewWithTopButtons is a view containing the 3 top buttons
self.navigationItem.titleView = viewWithTopButtons
To add the burger menu functionality on a UINavigationController you can find several posts on how to do it and infinite frameworks you can use. Check this other SO Question for a more detailed answer (e.g. MMDrawerController, ECSlidingViewController to mention a couple).
About organizing your view hierarchy, it really depends on if when the user taps one of the main top buttons, it will always go to the first view controller in the new section or if you want to bring him back to the last view in the section where he was.
3.1 Switching sections displays the first view of the new section
Your app's UIWindow will have a single UINavigationController on top of the hierarchy. Then each of the 3 top buttons, when tapped, will change the root view controller of the UINavigationController.
Then, when the user changes section, the current navigation hierarchy is discarded by setting the new section view controller as the UINavigationController root view controller.
self.navigationController = [sectionFirstViewController]
3.2 Switching sections displays the last displayed view in the new section
This will require a slightly modified version of the above, where your each of your sections will have its own UINavigationController, so you can always keep a navigation hierarchy per section.
Then, when the user taps one of the top buttons to switch section, instead of changing as previously described, you will change the UIWindowroot view controller to the new section's UINavigationController.
window.rootViewController = sectionNavigationController
Using a custom implementation
Of course, the last and also very valid option would be that you implement yourself your own component to achieve your requirements. This is probably the option requiring the biggest effort in exchange of the highest customizability.
Choosing this option is definitely not recommend to less experienced developers.
I'd like to take a stab at this--I think it is possible to use a tab bar controller here.
Your topmost-level view controller will be a UITabBarController with a hidden UITabBar.
Each tab is contained in a UINavigationController.
All view controllers in the navigation controller will be a subclass of a view controller (say, SwitchableViewController).
In SwitchableViewController's viewDidLoad, you set the navigation item's title view (i.e. whatever's at the center; self.navigationItem.titleView) to be the view that holds the three center buttons. Could be a UISegmentedControl, or a custom view.
Whenever you tap on any of the buttons, you change the topmost UITabBarController's selected index to the view controller you want to show.
Issues you may encounter:
Table views inside tabs will have a scrollIndicatorOffset at the bottom even if the tab bar is hidden.
Solution: Play around with the automaticallyAdjustsScrollViewInsets of the tab bar controller, or the inner view controller. https://stackoverflow.com/a/29264073/855680
Your title view will be animated every time you push a new view controller in the navigation stack.
Solution: Take a look at creating a custom transition animation for the UINavigationController.
I have set up a view controller in Storyboard which is embedded in a navigation controller. In this nav controller I have checked Shows Navigation Bar and Shows Toolbar and enabled a navigation bar and toolbar in Top Bar and Bottom Bar respectively in Simulated Metrics. I then "Show e.g. Push" segue from the view controller to another view controller. On both view controllers I've set up Simulated Metrics the same way, so both the navigation bar and toolbar are visible on all three controllers.
The problem is, I can add bar button items to the first view controller to both the navigation bar and the toolbar, but I cannot add a bar button item to the navigation bar on the second view controller. When I drop a button on the navigation bar, it's added to the toolbar instead. And I cannot double click the nav bar to add a title. In the outline I see there is no navigation item on the second view controller, but it is there in the first view controller.
I can probably add buttons to the navigation bar programmatically, but I want to do this visually in Storyboard. My question is, what is wrong with this setup, or is this a bug with Xcode?
For XCode 6, the UINavigationItem for the 2nd view controller onwards is not added automatically on the View Controller Object inside the storyboard. You will have to drag the UINavigationItem onto the Navigation Bar for that view Controller Object before adding UIBarButtonItem on top of it.
I am not sure why it is designed that way. I only discovered about this a few weeks ago.
If you have a ton of view controllers and very little custom auto-layout stuff in place, you can disable size classes, then re-enable it will add all missing nav bars across your storyboard.
Obviously not recommended if you have a ton of custom auto layout stuff linked up.
If you have just a single UIViewController that's missing a nav bar, just drop a UINavigationItem onto it.
If you're using Xcode 7 beta 4/5, try restarting Xcode it solved the issue for me
I just bumped into this issue and it seems to be affected by the segue that shows the view controller.
If "Kind" setting in segue is "Show (e.g. Push)", it's not possible to drag the item to top right corner. However, if you explicitly change "Kind" setting to "Push", this can be done.
Edit: actually I just noticed that "Push" is deprecated. Not sure what Apple is thinking here. However, you can just change it back to "Show" after adding the button and it seems to work :D
For second view controller in hierarchy, you can setup title in attributes, without adding "navigation item"
I think it is a bug. I had the same problem.I fixed this problem by disable the size classes, then enable it.
You can disable and enable the size classes in Interface builder doc.
It's very simple. You just need to use navigaitonItem first as the holder of the buttons and then you can add barButtonItems on top of that.
In my app, i have a main view controller which sometimes brings a modal view on top of it. This modal view is a UINavigationController with a navigation bar. I want to display an image above the navigation bar, and have the navigation bar appear below the image.
I do not want to subclass anything and the app uses autolayout, i do not want a bunch of delegate callbacks and frame calculations. The view inside the navigation controller (the actual modal content) must still respond to different screen sizes correctly, such as rotation, call status bar etc. Also, no IB solutions please, these views are all managed in code.
How do i accomplish this?
I would turn off AutoLayout and place the image at the top
I don't think you can do it with your modal view being a navigation controller. I would do it by making that modal controller a UIViewController that you set up as a custom container controller. You can add an image view to the top of this controller's view and add the view of a child view controller (which would be a navigation controller) to the bottom. This would be a lot easier to do in a storyboard using container views, but it certainly can be done in code.
I am completely new to ios development and I am only interested in developing for ios5.
I have an app with some scenes, they are mostly tableviews. I also use a navigation controller
I however need to add some status text and buttons that are always visible in all scenes and thought that a toolbar added to the navigation controller should do the trick.
so i thought that i should only have to drag out a toolbar in storyboard to the navigation controller, but it does not stick there. I can add it to the bar underneath with first responder and navigation controller but that does not help me (small icons).
I can also not add it to my table view (but if i drag out a plain view I can add it there)
do I have to make my own custom navigation class that the navigate view uses and then programatically add my toolbar?
Had the same question recently. Check Attributes Inspector in your ViewController's properties in storyboard. There you can define a Bottom Bar.
Well, inside the UINavigationController, you should have something... A UIViewController for instance. You can easily add a UIToolBar by dragging the object inside the UIView of the UIViewController. What might being happening is that as the root view you have the UITableView, in that case I think you can't do that. But to better understand, just take a small print screen of your StoryBoard.
If you zoom up to 100% on the storyboard it should drag.