I'd like to implement a top menu bar in an iOS app. I want it to be shown in every view controller. Whats the best approach besides using the bar from the navigation controller?
There are built in functionalities for iOS that allow you to have UI persist amongst many view controllers. Currently the UITabBarController and the UISplitViewController contain views at the bottom or left and persist among the other view controllers that are linked to be displayed. The UINavigationcontroller has a view at the top. If you wanted something else, then there is no standard iOS way of doing it, but here are 3 options.
Create a master view controller class that all class inherit from this one. Have what ui you would like to persist recreated via a singleton and added as a subview when you allocate the master class.
The top bar could be added as a subview to the UINavigationController. Subclass uinavigationcontroller and you can do [self.view addSubview:view].
Or add the ui to the window of the app. This can be done anywhere through out the app all you need to do is UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
[keyWindow addSubview:view];
I would suggest going with option 2, option 1 is too tedious for something so simple and option 3 would persist through out the entirety of the app, option 2 associates the view you add with the UINavigationController, therefore only the view controller in the navigation controller are affected, like wise if you remove the navigation controller the content goes with it.
Related
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'm curious about what's the best way to plan the controllers for my app.
i want my main screen to have 3 button.
1) should open a nav controller with details view
2) should open a controller with other buttons that lead to others controllers
3) should open a tab bar with 2 pages ( or eventually use a switch to change page instead of the tab bar)
this is the schema of what i want
http://i59.tinypic.com/2rrvrd4.png
Is it a correct schema or i should use my controllers differently? will apple reject an apple with such schema?
thanks
As #Fogmeister pointed out in the comments, going for a UITabBarController as the main interface for your app actually seems to be a more appropriate solution here.
However, you can go with the interface that you described, but then you should keep in mind that with your current setup, you are not only using UINavigationController in the first case, but your whole navigation system is still built upon UINavigationController in the following way:
Your app has one instance of UINavigationController.
Your initial UIViewController (the one with the three buttons), is the rootViewController of your UINavigationController.
You can navigate to the other view controllers using [self.navigationController pushViewController:newViewController] (or performSegue if you prefer using Storyboards).
In the case of your third view controller, you are pushing a UITabBarController onto the navigation controller's view controller stack, this UITabBarController needs to be initialized with the two view controllers that it is going to display before it gets pushed onto the stack.
I've tried a lot to get this done.I don't want want to use addsubview or uitabbarcontroller. I want to switch the view when I tap on different tabs and tabbar should stay there. Thanks a lot in advance.I m a newbie.I want to use uitabbar not uitabbarcontroller.
A simple approach would be to wrap the view controllers you are inserting in UITabBarController in a UINavigationController then you can simply push your new view to that UINavigationController and the tab bar would be always visible!
For more details refer Apple Docs
Edit:
If you don't want to use UITabBarController then you need to do 2 things:
Add the tab bar View to UIWindow that way it would be always visible.
Scale/adjust the views in your view controllers to leave space for the tab bar
I am developing an app where I am using the side moving menu like in the facebook app:
I want to keep that bar up top present through out the app and have the UINavigationControllers get swapped in and out of it for the different sections of the app for Item1 ... ItemN.
How can I go about doing this?
Just add it to the window in AppDelegate:
[[[UIApplication sharedApplication] delegate].window addSubview:yourView];
Frankly, you should cast the delegate that comes from sharedApplication
I solve this by using a custom container view controller. My rootViewController is just a container view controller which holds my menu and the normal view controller. This allows me to do whatever I want to with the menu, but just slide the menu off the screen and have the child view controller act like it controls everything.
"Implementing a Container View Controller" is a section in the UIViewController Class Reference and holds some good information on how to accomplish the task. There are also a fair number of good videos from Apple at the WWDC when they were introduced in... 2011?
Edit: Added info on custom view controllers.
I solved this issue using child view controllers on the "central" view.
I simply made the top most persistant menu a subview that rested on top of the child view controller's view.
I understand that view controllers help control multiple views in an application, but I have trouble understanding when to use them.
If I have an application with a main page, several views with a "hierarchy" structure, and an about page not connected with the hierarchy, what files should my application have? An appdelegate, navigation controller and view controller? More than one view controller? Just a navigation controller?
Also, should they all be contained in one .xib file, or multiple .xib files?
Any help would be greatly appreciated.
Thanks.
A good habit is to have a UIViewController for each page you want to show. If I get the structure of your app you should have a main page (with many other UIViews inside it) and another page (about page). If that's true I suggest two UIViewControllers.
The UINavigationController is a subclass of UIViewController that lets you "navigate" among the pages. It's not strictly necessary but suggested (you can also implement your self a custom navigation system, but it's easier to exploit the one Apple offers you). Another navigation system is the one based on UITabBarController, if you want to take a look.
Assuming I get the structure of your app you should need two .xib file, one for each page you have.
The app delegate is conceptually different from a view controller, you'll have just a single app delegate, automatically created by Xcode (you can, of course, modify it to fit your needs).
Each "screenful of content" (Apple uses this term) should be handled by it's UIViewController or more likely a subclass of it. The point of view controller is to handle view appearing or disappearing (going on/offscreen), device rotation, memory management, navigating to other view controllers and so on. If you are creating your UI with IB, then each of those view controllers would most likely have it's own .xib file.
Each view controller has one view (it's view property) that acts as main view for each "screenful of content" to which you then add your subviews.
UINavigationController and UITabBarcontroller are there to help you control the hierarchy of your app. They only act as containers for other view controllers and don't contain any UI except navigation bar or tab bar. Using tab bar controller you can have multiple view controllers which act exactly like browser tabs. Using navigation controller you can have a stack-like navigation where new view controllers are pushed from right to left and are popped from left to right when user goes back to previous view controller. You can even have a view controller inside navigation controller inside a tab bar controller.
If you don't want to use tab bar or navigation controller, you can navigate through your view controllers by presenting them modally using presentModalViewController:animated: and dismissing by dismissModalViewControllerAnimated:. If you send YES for animated parameter of these methods, you will get an animation specified by the modalTransitionStyle property of view controller being presented or dismissed. Possible animations are slide in from bottom (default), horizontal flip of entire screen, fade in/out and half-page curl.
There are also some Apple-provided subclasses of UIViewController that help you setup your UI quicker like UITableViewController which is basically a view controller that contains a table as it's main view and conforms to 'UITableViewdataSourceanddelegate` protocols which are required to define how each cell looks and what it contains.
On iPad there is one additional container controller UISplitViewController and one additional way to present new view controllers using UIPopover.