Stopping navigation bar from scrolling with table - objective-c

I have a UITableViewController which successfully lists in the table view data fetched from a CoreData entity.
I want to have a navigation bar at the top with a couple of buttons to navigate around, but when I add the navigation bar it appears to sit inside the table, bellow any listings, and therefore scrolls wit the table when flicking through the table list.
As it is a UITableViewController I cannot make the table area smaller it seems and so I have no idea how to add the navigation bar outside of the table.
Any advise on how to make the fix the navigation bar in place so that it does not move.
Here is the code use to set the navigation bar:
- (void)viewDidLoad
{
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0,0, 1024,44)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:#"Observation details"];
[navBar pushNavigationItem:navItem animated:NO];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(backButton)];
navItem.leftBarButtonItem = backButton;
UIBarButtonItem *detailsButton = [[UIBarButtonItem alloc] initWithTitle:#"Observation Details" style:UIBarButtonItemStyleBordered target:self action:#selector(detailsButton)];
navItem.rightBarButtonItem = detailsButton;
[self.view addSubview:navBar];
}

Don't drag the navigation bar and drop on the table view. That way you are setting that view (a navigation bar) as the header of the table view.
To do what you are trying to do, the easiest way is to use a navigation controller with the table view as its rootTableView.
myNavController = [[UINavigationController alloc] initWithRootViewController:myVC];
[self presentViewController:myNavController ...
You can also use a navigation bar without a navigation controller. For that, you have to set a View with a navigation controller at the top and a table view filling the rest of the view.

There are several ways to achieve this. I try to describe the one of which I believe it is easiest based on what I guess is your current level of experience.
Create a new empty view with a separate view controller.
Add two subviews to that view of the type container view. These views are designed to carry views that have their own view controllers. One of these containers is on top and has the size of the navigation bar and contains the navigation bar etc.
For that one you could create a separate view controller. However, I see no reason why that could not be the same view controller. (File's owner in IB)
It may well be a separate instance/class. That is up to you.
The remaining view is occupied by the second container view. This one contains a UITableView for which a UITableViewController (-subclass) is the File's Owner.
Unless you are more familiar with the view hierarchy and view controller hierarchy you should not break with the pattern (as given by default sceleton code and tutorials etc.) of having a 1:1 relation between table view controlers and table views. A UITableViewController has a view property as every UIViewController has. But for a UITableViewController that must be a UITableView and nothing else. The standard UITableViewController is not capable of dealing with a UIView as view property that contains a table view and other views as siblings. Plus it is not a good idea of adding more subviews to the table view with respect to its scrolling behaviour etc.
By separating them you can deal with the table and still take examples straigt of tutorial code plus you can have a navigation bar on top that is not influenced by the table at all.
However, I should mention that you could get all of this much easier by using a proper navigation controller. That would bring in your navigation bar for free. You must have good rasons for not doing so.

Related

How to create a tab bar on iOS?

I need on my main view controller to have a tab bar with tabs to navigate to all my other controllers. I just need the tab bar on this controller and when i get to another controller i just need to have a back button to go to the main controller.
Now i have some questions. I created the tab bar in the main view controller and all the tabs with the text and images that i need. However i see that i can only create IBOutlet for the tab bar and not IBActions for every tab(as i thought). So i created an IBOutlet and connected it to my tab bar.
How can i refer to every tab?
If i can refer to every tab how is it possible to change the view controller when a tab is selected when i cant use an action about it?(I am not asking for the code to change controllers , i am asking for the place that i should put the code so that my application knows that this specific tab was pressed and has to change controller).
Thank you for reading my post :D
You can create a UITabBarController programmatically in applicationDidFinishLaunching and set it as the root view controller (or if you prefer, you can present it as a modal view). Here is the minimal code to do it:
UITabBarController *tabBarController = [[UITabBar alloc] init];
UIViewController *controller1 = [[YourViewController alloc] init];
UIViewController *controller2 = [[YourOtherViewController alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects:
controller1,
controller2,
nil];
// set as the root window
window.rootViewController = tabBarController;
If you want to customize the look of the tab bar items, do so by adding overloading (UITabBarItem *)tabBarItem in the child view controller(s):
- (UITabBarItem *)tabBarItem
{
return [[UITabBarItem alloc] initWithTitle:#"Amazing" image:[UIImage imageNamed:#"Blah.png"] tag:0];
}
How to make a tab bar controller
by me
Drag tab bar controller into storyboard (hopefully you have one)
Control-drag from tab bar controller to each view you want hooked up to it
Pop bottles
Just so you know, this gives you the default tab bar controller behavior (so it will always be present and you can click from any page to another). If that's not what you want, then don't use a tab bar controller. To do otherwise is an abomination.
Storyboards are definitely helpful, but if you don't want to use one that's fine. Doing the Control Drag from the Tab Bar Controller to your new View Controller does indeed work (Dustin's response).

Setting up and using the UINavigationController class in Objective-C

I am trying to use the UINavigationController class in Objective-C, but I am having a difficult time understanding how it should work.
Basically, I have my app. I want to use the UINavigationController to show a hierarchy of data stored in an NSArray. I currently have this data being presented in UITableView. I want to make it so a user can click on a row of the table view and be taken to more specific data about the row they just clicked. I think a UINavigationController is perfect for this.
However, my understanding of MVC in the context of Objective-C is not that good and I am confused about how to do this. I want the UINavigationController to only show up in the left half of my iPad app and I would also like the ability to hide it at times. So how do I configure this?
This sounds like the correct usage for a navigation controller.
What you will need to do is create your navigation controller and populate the root view with your view controller containing the table view. In your didSelectRowAtIndexPath you would push the detail view onto the stack. All the navigation will be set up to go back for you.
Most likely in your AppDelegate:
ListViewController *theView = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
UINavigationController *navView = [[UINavigationController alloc] initWithRootViewController:theView];
[theView release];
[window addSubview:navView.view];
[window makeKeyAndVisible];

Top Bar does not appear for presentModalViewController

I've created a UIViewController subclass called addItemToListViewController. I selected add an "xib" as well, and just created a simple page with a couple of labels and a textField. In the interface builder I selected "Top Bar - Navigation Bar" so that when it is put on the stack when the application runs it will have a top bar that will match the initial main window. In the Interface builder it shows the top border, but when I run the application in the simulator the top bar is not present once the view is displayed.
Here is the code I placed in the rootViewController to present the view controller
- (IBAction)addButtonPressed:(id)sender
{
AddItemToListViewController *addItemToListViewController = [[AddItemToListViewController alloc] initWithNibName: #"AddItemToListViewController" bundle:nil];
[self presentModalViewController: AddItemToListViewController animated: YES];
[AddItemToListViewController release];
}
I'm only able to have the top bar present if I manually add a Navigation bar to the xib. If I must add a Navigation bar to my xib, what is the purpose of the "Top Bar" attribute?
- (IBAction)addButtonPressed:(id)sender
{
AddItemToListViewController *addItemToListViewController = [[AddItemToListViewController alloc] initWithNibName: #"AddItemToListViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addItemToListViewController];
[self presentModalViewController: navController animated: YES];
[AddItemToListViewController release];
[navController release];
}
That "top bar - Navigation bar" in InterfaceBuilder is what's known as a "Simulated Metric". It's there to help you lay out your view with correct spacing when other visual elements - the status bar, navigation bar, or tab bar - might consume some of the device's screen real estate. It doesn't actually do anything other than shrink the vertical dimensions of the view defined by the NIB. The purpose is to help you layout your view, not to actually create a component that will appear in your app.
If you want a navigation bar, then you have two choices. The first choice is to use a navigation controller (of which your initial view will have to be the root) and call
[self.navigationController pushViewController:newVC animated:YES];
The process of setting up a navigation controller correctly, etc, is nontrivial, and you should do some searching to find the best way to do that for your app. For a simple app, especially if you're just learning iOS, you can use the "Navigation-based Application" template when you create a new project. With a navcon, you get all the fancy behavior normally associated with that top bar - an automatic back button, fancy left/right scrolling when you transition to a detail view, etc.
The second option is to put a "fake" navigation bar in the detail view, using the Navigation Bar object. You can find that object, plus some other related objects, in the bottom half of the "Utilities View" (the right-most pane) in XCode. Just drag the object into your XIB and blammo, you have a 44-pixel tall gray bar. This navigation bar is just like what you get when you use a Navigation Controller except you don't get the stack functionality; you can still add buttons to the left and right, change the title, tint it to a specific color, etc.
The xib does not know you will use the controller as a modal view as it could also be used for a normal view which could show a top bar. Only when you push the view it will use or ignore the showing of this top bar.
In short: its there in case you will use the xib for a normal view :)

Adding a Navigation Controller to a View based Application adds top margin

I am trying to programmatically add a Navigation Controller to my View based Application. This is the code I am using (this code gets called after a button press in a view controller):
MainMenu *control = [[MainMenu alloc] initWithNibName: #"MainMenu" bundle: nil];
UINavigationController *navControl = [[UINavigationController alloc] initWithRootViewController: control];
[self.view addSubview:navControl.view];
[control release];
That works, but this ends up happening:
Notice the odd margin above the Navigation control.... My View controller that I am adding the Navigation Controller to has a gray background which you can see.
Any ideas??
If you have a better way of adding a Navigation Controller to a View based Application I am very open to suggestions!
Thank you in advance!
Thank you both for your response, but unfortunately, wantsFullScreenLayout set to YES or NO in the code didn't have any effect. I was able to push the Navigation Controller up by 20 using this line of code:
self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -20.0);
but then what happened was that the View Controller did not move up with the Navigation bar and left a gap below the Navigation Bar and the View Controller. What eventually worked was checking the Wants Full Screen checkbox in IB in the MainWindow view controller that is automatically generated when you set up a view based application.
The gap you are seeing is the same height as a status bar. Check the status bar settings in your NIB file.
Chances are you want to make the UINavigationController the root view controller for the window, rather than whichever view controller you have now. That would be the better way to do it.
The reason you're seeing that extra margin at the top is because UINavigationController normally expects that it will be sized to fill the entire screen (except perhaps a tab bar at the bottom, if it's inside a UITabBarController), and therefore expects that the top edge of its view will be under the status bar if the status bar is visible. Therefore, it places its navigation bar 20 pixels below the top of its view to leave space for the status bar, without bothering to check whether its view actually is under the status bar. Interestingly, sometimes a re-layout operation will perform this check, but that's unreliable. What I've found works well in a situation like this is to set the UINavigationController's wantsFullScreenLayout property to NO. Then ti doesn't try to leave room for the status bar, so everything works as expected.
I've been struggling with this same issue this morning. Since setting the wantsFullScreenLayout property doesn't seem to have any effect, I resorted to using a little subclass, which worked fine:
#interface MyNavigationController : UINavigationController
#end
#implementation MyNavigationController
- (BOOL)wantsFullScreenLayout;
{
return NO;
}
#end
Its so simple to remove that gap..
self.navigationBar.view.frame = CGRectMake(0, -20, 320, 480);

tableView footer strange behavior

Given: I have a bit of a "pop up" view that I put over my tableView within my UITableViewController. I put it there like this:
[self.navigationController.view addSubview:self.hoverView];
Problem: I cannot see this hoverView when I add a tableView footer view. Seemingly unrelated yes?
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[self.tableView.tableFooterView addSubview:someLabel];
These appear to be mutually exclusive. I can have one, but not the other. To see what's going on, I print subview descriptions like so:
for (UIView *sub in self.navigationController.view.subviews)
{
NSLog([sub description]);
}
When the table footer view is added, this code prints nothing. Otherwise, I see the expected output of some navigationController internal views. What did I miss?!
Don't add the hoverView to the UINavigationController's view. Instead of using a UITableViewController, use a UIViewController whose view contains a UITableView as a subview. (See here for details of how to implement the rest of the UITableViewController's functionality in your UIViewController). Then add your hoverView to that view, i.e., make it a sibling of the UITableView, but a later sibling so it appears above it.
This may not solve your problem but I'd say it's your best bet: a UINavigationController is not designed to have its view manipulated directly, it's designed to have view controllers pushed onto its stack and add subviews to its view accordingly.