I have added a navigation controller inside a viewcontroller thats inside another navigation controller... lol
well anyway because of this structure I have an issue with any views I push to the "sub"navigation controller.. because its only fitting inside the grame of the "parent" navigation controller its pushing the pushed views contents down by about 20/40pxl...
I was wondering how I get stop this from happening.. here are two pictures showing you what is happening.
where the label is clearly centered in Interface builder
This is the code I have so far for this stuff.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Init the (sub)navigationController
otherNav = [[UINavigationController alloc] init];
// Add this (sub)NavController to the current viewcontroller (which is inside the (parent)navcontroller)
[self.view addSubview:otherNav.view];
// Hide the (sub)NavControllerbar
otherNav.navigationBar.hidden = YES;
// Load a detial view into the (sub)NavController
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:[NSBundle mainBundle]];
[otherNav pushViewController:detailView animated:NO];
}
The otherNav is also set up in the .h file for global access in this view.
When the "super" NavigationBar is visible, the self.view.frame.height is:
480-20-44 (actualViewheight-statusbarheight-navigationBarheight).
There are 2 solutions for your problem.
1. For simplicity I would say, if your only problem is to make it centralized.
[self.view addSubview:otherNav.view];
[otherNav.view setCenter:self.view.center];
This will make your label center alligned.
2.Though, if you are using interface builder;
select the xib file.
select the view.
open Utilities.
set the Top bar as Navigation bar.
then the things you will align you will get as it is on device/simulator or what ever you are testing on.
Related
I implemented a custom tab bar controller as a set of buttons each one related to it's own View Controller. I guided on this link http://idevrecipes.com/2011/01/04/how-does-the-twitter-iphone-app-implement-a-custom-tab-bar/ to achieve the behavior. So the relevant part of code is as follows:
- (void) selectedItemAtIndex:(NSUInteger)itemIndex
{
// Get the right view controller
NSDictionary* data = [self.tabBarItems objectAtIndex:itemIndex];
UIViewController* viewController = [data objectForKey:#"viewController"];
// Remove the current view controller's view
UIView* currentView = [self.view viewWithTag:SELECTED_VIEW_CONTROLLER_TAG];
[currentView removeFromSuperview];
// Set the view controller's frame to account for the tab bar (+ 48)
viewController.view.frame = CGRectMake(0,48,self.view.bounds.size.width, self.view.bounds.size.height - 48);
// Se the tag so we can find it later
viewController.view.tag = SELECTED_VIEW_CONTROLLER_TAG;
// Add the new view controller's view
[self.view insertSubview:viewController.view belowSubview:self.tabBar];
//Keep track of current view controller
self.currentController = viewController;
}
So far is working, I can see each view controller in a similar maner to the default TabBarViewController. But then there's a requirement where I need to push a new navigation controller modally (it should take all the application frame) from inside one of the tabBar controllers.
At first glance I tried the following code from within one of the tab controllers:
DetailViewController *detailViewController = [[DetailViewController alloc]init];
UINavigationController *navigationController = [[UINavigationController alloc]detailViewController];
[self presentModalViewController:navigationController animated:YES];
However is not working as expected, first the view is shown below the TabBar and second the new view is not taking in consideration the parent view frame which should be the screen bounds less the tabbar. (0, 48, 360, 412). My detail view controller it's loading content from a nib file.
Well, this is quite obvious since the TabBar Controller is inserting each view below my custom TabBar.
[self presentModalViewController:navigationController animated:YES];
So I tried inserting it directly as a window subview:
[[UIApplication sharedApplication].keyWindow addSubview:navigationController.view];
But, I think this is not okay... there should be a better approach that I can't figure out. So if anybody could give me suggestions on how to correct or improve this navigation system it would be great.
Thanks a lot.
If you are building you app for iOS 5.0 and up you can make use of childViewController. In your custom Tab Bar you can have a containerView and a tabView.
The view of viewController is added to containerView. All the necessary events are generated to the subsequently added viewController if the following methods are implemented correctly
- (void)addChildViewController:(UIViewController *)childController;
- (void)removeFromParentViewController;
More about viewController containment can be found here.
I have a Navigation application that has a view controller in it.. I am now trying to load another NavigationController into that ViewController however I am experiencing problems..
I am trying to do it programmatically because I am not sure how to do it in InterfaceBuilder however the new navigation controller displayes weird.. like it thinks there is a infobar above it.. so has a white gap..
As you can see here.
This is all I am doing to get this ^ current look....
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UINavigationController *newNav = [[UINavigationController alloc] init];
[self.view addSubview:newNav.view];
newNav.navigationItem.title=#"Navigation Controller Example";
}
Any help would be greatly appreciated.
As you say,you just have an Navi-based App, so if you want to add another NavigationController in your application ,you should hide the new NavigationController's bar .Following is the code.
[newNav setNavigationBarHidden:YES animated:YES];
I'm trying to switch between several table views as the root of a navigation controller. Depending on the settings of my app, I want to use different sets of data with different methods, and prefer to have these encapsulated in separate classes.
My thought was to set a view manager class (UIViewController) as the root view controller of the navigation controller. In the view manager we check the settings to see which view we want to load:
if([application_mode intValue]==APPLICATION_MODE_A){
AViewController *aView = [[DeviceTableViewController alloc] init];
[self.view insertSubview:aView.view atIndex:0];
}
else if([application_mode intValue]==APPLICATION_B){
BViewController *bView = [[BViewController alloc] init];
[self.view insertSubview.bView.view atIndex:0];
}
That does in fact insert the appropriate view into the view manager, at the cost of a white bar at the top of the inserted view and no info on the navigation bar, ie the subview is not connected to the navigation controller.
What's the proper way to do this? I'd really prefer not to have one ginormous table view!
Where do you set your navigationController's rootViewController? Can't you just set it to an AviewController's object or an BViewController's object at this time ? You may not need an intermediate UIViewController
I would do at the beginning :
//navigationController comes from a Xib or previous code
if([application_mode intValue]==APPLICATION_MODE_A){
AViewController *aView = [[DeviceTableViewController alloc] init];
navigationController.rootViewController = aView;
[aView release];
}
else if([application_mode intValue]==APPLICATION_B){
BViewController *bView = [[BViewController alloc] init];
navigationController.rootViewController = bView;
[bView release];
}
Since there is no view controller containment, I like the approach outlined in Jonah William's blog:
http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/
You can't effectively place a view controller inside another; instead, we create something with similar lifecycle methods (viewDidLoad, viewDidAppear, etc) and forward those methods from the parent to the child. This 'psudo-viewcontroller' has a view property that we add as a subview to the parent's view, using UIView addSubView
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/addSubview:
With this approach, we can encapsulate view elements, switch them out dynamically in a view controller, place several within a single view controller, etc. This way they can be considered separately from your navigation stack. It's a bit of work, but the cleanest UI encapsulation approach in iOS 4 in my opinion.
I'm trying to present a TabBarController on top of another TabBarController. My application's MainWindow.xib looks like this:
Files Owner
First Responder
My App App Delegate
Window
TabBarContoller
+TabBar
+Nav Controller Subclass (a custom class)
+Navigation Bar
+Table View Contoller Subclass (custom class)
+Tab Bar Item
+Second View Controller (not yet hooked up)
I'm trying to display a xib file when an item is clicked in the TableView. This xib file has a TabBarController as it's main view, but when the view displays, the tab bar and navigation bar are both invisible. The code I'm using to display it is:
MyAppAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.customNavController presentModalViewController:customDetailEditViewController animated:YES];
If I use the code below to push the view controller onto the stack, I see the correct navigation bar, but the TabBar from the root view controller is shown instead of the one from the view which has been pushed.
[delegate.customNavController pushViewController:customDetailEditViewController animated:YES];
I even tried removing the TabBarController and manually implementing my own TabBar delegates but the same effect occurs (either no NavigationBar or TabBar, or the NavigationBar/TabBar from the root ViewController).
EDIT: I've uploaded the source to http://mi6.nu/tabcontroller.zip . I'd really appreciate it if someone with a bt more experience with iOS could take a look.
EDIT2: The closest I've come so far is presenting a modal view controller inside the first tabbar, so my view looks like this:
NavigationBar
[ ]
[ ]
[---View---]
[ ]
[ ]
TabBar from the pushed view
TabBar from the root view
To achieve this, I'm using:
UITabBarController *tabBarController = [[UITabBarController alloc] init];
UIViewController *directionsView = [[UIViewController alloc] init];
txtDirections = [[UITextView alloc]initWithFrame:CGRectMake(0,0,self.view.frame.size.width, self.view.frame.size.height)];
[directionsView.view addSubview:txtDirections];
IconPickerViewController *iconPicker = [[IconPickerViewController alloc]init];
tabBarController.viewControllers = [NSArray arrayWithObjects:recipeDetailEditViewController,directionsView,iconPicker, nil];
[directionsView release];
[iconPicker release];
MyAppAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.rootNavController presentModalViewController:recipeDetailEditViewController animated:YES];
This just complicates everything though, since a) It's not ideal as I have two tabbars and b) all controls (all of the editing controls) need to be in the TableViewController so their values can be loaded/saved to edit items. It would be much easier if the pushed view could handle loading/saving and appear on top of the root tabs.
Surely this must be possible?
This was an absolute nightmare, but I eventually got it working by presenting the view modally from the TableViewController when the add button is clicked:
[delegate.rootController presentModalViewController:recipeDetailEditViewController animated:YES];
delegate.rootController is the root TabBarController
The XIB file I'm presenting does not have a TabBarController, but rather a UIView, a Navigation bar and a TabBar. This appears to work when presented modally from inside a NavigationController.
Why are you putting everything in your main.xib?
Try moving the second tab bar out of the main window xib and instead put it inside the customDetailEditViewController.
I am showing a modal view which is a UITableViewController class. For some reason it won't show the navigation bar when I show it. Here is my code:
SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
detailViewController.navigationController.navigationBarHidden = NO;
[self.navigationController presentModalViewController:detailViewController animated:YES];
detailViewController = nil;
[detailViewController release];
I thought it was shown by default? If it helps, I am calling this from another class that is also a UITableViewController managed by a UINavigationController. Ideas?
When you present a modal view controller it does not use any existing navigation controllers or navigation bars. If all you want is to display a navigation bar, you need to add the navigation bar as a subview of your modal view and present it as you're doing.
If you want to present a modal view controller with navigation functionality, you need to present a modal navigation controller containing your detail view controller instead, like so:
SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[detailViewController release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:navController animated:YES];
[navController release];
Your modal controller will manage its own navigation stack.
Here is one way to display navigation bar for those who are using storyboards, suggested by Apple's Tutorial on Storyboard.
Because a modal view controller doesn’t get added to the navigation stack, it doesn’t get a navigation bar from the table view controller’s navigation controller. To give the view controller a navigation bar when presented modally, embed it in its own navigation controller.
In the outline view, select View Controller.
With the view controller selected, choose Editor > Embed In > Navigation Controller.
On iOS 7 and you just want a navigation bar on your modal view controller to show a title and some buttons? Try this magic in your UITableViewController:
// in the .h
#property (strong) UINavigationBar* navigationBar;
//in the .m
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = #"Awesome";
self.navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectZero];
[self.view addSubview:_navigationBar];
[self.navigationBar pushNavigationItem:self.navigationItem animated:NO];
}
-(void)layoutNavigationBar{
self.navigationBar.frame = CGRectMake(0, self.tableView.contentOffset.y, self.tableView.frame.size.width, self.topLayoutGuide.length + 44);
self.tableView.contentInset = UIEdgeInsetsMake(self.navigationBar.frame.size.height, 0, 0, 0);
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//no need to call super
[self layoutNavigationBar];
}
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[self layoutNavigationBar];
}
I want to share how the accepted solution can be used in projects with storyboards:
The simple approach is to put in a storyboard blank navigation controller before the VC which is to be presented modally, so the relations look like:
(Presenter VC) -> presents modally -> (navigation controller having a controller to be presented as its root).
We've tried this approach for a while and noticed that our storyboards become "polluted" by a large number of such intermediate navigation controllers when each! of them is used exclusively for one! presentation of some other controller, that we want to be presented modally with navigation bar.
Our current solution is to encapsulate the code from accepted answer to a custom segue:
#import "ModalPresentationWithNavigationBarSegue.h"
#implementation ModalPresentationWithNavigationBarSegue
- (void)perform {
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.destinationViewController];
[self.sourceViewController presentViewController:navigationController animated:YES completion:nil];
}
#end
Having this segue in our project we do not create intermediate navigation controllers in our storyboards anymore, we just use this ModalPresentationWithNavigationBarSegue like:
Presenter VC --> Presentee VC
I hope that this answer will be helpful to people who like to avoid unnecessary duplication in their apps storyboards.
I just wanted to add something to what #Scott said. His answer is definitely the easiest and most accepted way of doing it now with Storyboards, iOS 7 and 8... (and soon, 9).
Definitely adding a view controller to the Storyboard and Embedding it as described by #Scott is the right way to go.
Then, just add the segue by control-dragging from the source view controller to the target (the one you want to show modally), select "Present Modally" when the little view appears with the choices for the type of segue. Probably good to give it a name too (in the example below I use "presentMyModalViewController").
One thing that I needed that was missing is #Scott's case is when you want to actually pass on some data to that modally-presented view controller that is embedded in the navigation controller.
If you grab the segue.destinationViewController, it will be a UINavigationController, not the controller you embedded in the UINavigationController.
So, to get at the embedded view controller inside the navigation controller, here's what I did:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"presentMyModalViewController"]) {
// This could be collapsed, but it's a little easier to see
// what's going on written out this way.
// First get the destination view controller, which will be a UINavigationController
UINavigationController *nvc = (UINavigationController *)segue.destinationViewController;
// To get the view controller we're interested in, grab the navigation controller's "topViewController" property
MyModalViewController *vc = (EmailReceiptViewController *)[nvc topViewController];
// Now that we have the reference to our view controller, we can set its properties here:
vc.myAwesomeProperty = #"awesome!";
}
}
Hope this helps!
If you only need a NavigationBar, you can add an instance of UINavigationBar and assign BarItems to it.