I created a simple project to demonstrate this strange behavior. I created all of this in the interface builder without touching the code so that it's easy for you to reproduce.
The start page is embedded in the navigation controller containing only one button, and when clicking on it, the screen will be directed to the tab views (with navigation bar on the top).
There are 2 strange things happening when running the program.
1) The tab item2's table view is underneath the navigation bar where as the item1's is displayed correctly.
vs.
As you can see, although the two table view is placed in the exact same position, when the program runs, the second one even hides the search bar because of the incorrect alignment.
2) When clicking on the search bar in tab item1, the navigation bar is not hidden as the default behavior (where the nav bar hides and the search bar shows instead).
Since the nav bar is semi translucent, I can see the 'Cancel' button underneath the nav bar.(Any one with a good eye can see the blue tint at the upper right corner of the screen shot). It means the search bar goes to the correct location but the nav bar just doesn't go away.
Also, note that the table view is not shifted up with the search bar(again, default behavior) when the search bar is active.
PS: I am using XCode 6. Also I tried adding constraints to the tableviewcontrollers, but no dice.
Any ideas on this? Thanks in advance.
As logixologist suggested, you can put a navigation controller for each tab as the first controller of the tab. If you don't want to do that, you can add the following code in viewDidLoad of second item view controller.
CGFloat shiftDist = CGRectGetHeight(self.navigationController.navigationBar.frame) + CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
self.tableView.contentInset = UIEdgeInsetsMake(shiftDist,0, 0, 0.0f);
self.tableView.contentOffset = CGPointMake(0, -shiftDist);
After that, there is problem for rotation. You'll notice if you rotate to landscape, the search bar doesn't stick under the navigation bar. Here is how to fix it.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0);{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
CGFloat heightBeforeRotation = CGRectGetHeight(self.navigationController.navigationBar.frame) + CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
CGFloat offsetY = self.tableView.contentOffset.y;
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
CGFloat heightAfterRotation = CGRectGetHeight(self.navigationController.navigationBar.frame) + CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
self.tableView.contentInset = UIEdgeInsetsMake(heightAfterRotation,0, 0, 0.0f);
self.tableView.contentOffset = CGPointMake(0, heightBeforeRotation + offsetY - heightAfterRotation);
}];
}
The issue is how the Tab Bar Controller is presented. Tab Bar Controllers are special and generally should be the initial view controller in your storyboard.
If the Tab Bar Controller is not the initial view controller then it should be presented modally. In my test app I changed the segue to "Present Modally".
Then added a Navigation Controller for each Tab bar Table View Controller with a done button that dismissed the modal Tab Bar Controller.
- (IBAction)DoneButton:(id)sender {
[self.parentViewController dismissViewControllerAnimated:YES completion:nil];
}
Per Apple's Documentation "View controller Catalog for iOS"
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html
Adding a Navigation Controller to a Tab Bar Interface
An app that uses a tab bar controller can also use navigation
controllers in one or more tabs. When combining these two types of
view controller in the same user interface, the tab bar controller
always acts as the wrapper for the navigation controllers.
The most common way to use a tab bar controller is to embed its view
in your app’s main window. The following sections show you how to
configure your app’s main window to include a tab bar controller and
one or more navigation controllers. There are examples for doing this
both programmatically and using Interface Builder.
Tab bar views do not support translucency and tab bar controllers
never display content underneath their associated tab bar. Therefore,
if your navigation interface is embedded in a tab of a tab bar
controller, your content may underlap the navigation bar if you adopt
a full-screen layout as described in Adopting a Full-Screen Layout for
Navigation Views, but it does not underlap the tab bar.
When embedding navigation controllers in a tab bar interface, you
should embed only instances of the UINavigationController class, and
not system view controllers that are subclasses of the
UINavigationController class. Although the system provides custom
navigation controllers for selecting contacts, picking images, and
implementing other behaviors, these view controllers are generally
designed to be presented modally. For information about how to use a
specific view controller, see the reference documentation for that
class.
Displaying a Tab Bar Controller Modally
It is possible (although uncommon) to present a tab bar controller modally in your app. Tab bar interfaces are normally installed in
your app’s main window and updated only as needed. However, you could
present a tab bar controller modally if the design of your interface
seems to warrant it. For example, to toggle from your app’s primary
operational mode to a completely different mode that uses a tab bar
interface, you could present the secondary tab bar controller modally
using a crossfade transition.
When presenting a tab bar controller modally, you always pass the tab
bar controller object as the first parameter to the
presentModalViewController:animated: method. The tab bar controller
must already be configured before you present it. Therefore, you must
create the root view controllers, configure them, and add them to the
tab bar controller just as if you were installing the tab bar
interface in your main window.
As with all other modally presented view controllers, the parent view
controller is responsible for dismissing its modally presented child
view controller in response to an appropriate user action. When
dismissing a tab bar controller though, remember that doing so removes
not only the tab bar controller object but also the view controllers
associated with each tab. The view controllers that are not visible
are simply removed, but the view controller displayed in the currently
visible tab also receives the usual viewWillDisappear: message.
For information on how to present view controllers (including
navigation controllers) modally, see Presenting View Controllers from
Other View Controllers in View Controller Programming Guide for iOS.
For information on how to configure a tab bar controller for use in
your app, see Tab Bar Controllers.
I would like to have my search bar launched from a UIBarButton that I have added to my navigation bar from the storyboard. I have also added the Search Bar and Search Display Controller to the document outline in my view controller from the storyboard.
If I implement the code below in my viewDidLoad method the search bar will automatically appear in my navigation bar self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
However, when I try and implement this in from a button click from my navigation bar nothing happens.
(IBAction)serachBarButton:(id)sender
{
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
}
The IBAction is properly hooked up to the view controller in the storyboard. Any code examples of how to launch the search bar from my navigation button click would be greatly appreciated.
I have an application that is supporting only ios7+ The navbar setup is using the new 64px high bar that appears beneath the status bar. Here is what it looks like when the app launches:
If I do any sort of "presentViewController", when i dismiss the view the navbar shifts back to 44px height and still appears underneath the status bar which in-turn makes all the contents of the view also shift up. Here is what that looks like:
It doesn't matter if I am presenting one of my own views or if I simply present a UIImagePickerView, any sort of slide up modal via the navigation controller breaks the navbar setup. Any ideas on how to fix this?
A few notes:
in plist: "View controller-based status bar appearance" is set to "NO"
navbar configured with self.navController.navigationBar.translucent = NO;
I am using .xib NOT Storyboards
UPDATE:
I have the navigation controller inside of a PKRevealController (https://github.com/pkluz/PKRevealController). Taking the reveal controller out and just adding the nav controller to the window itself fixes the issue... why would the reveal controller cause it to behave differently?
SOLUTION:
It turned out that the PKRevealController library was causing the issue. I reworked how it was set up in the AppDelegate and that solved the problem, although it's sorta of "hacky". I put my "before" and "after" configurations below:
the initial setup was :
configure PKRevealController
configure NavController and add rootView
set pkreveal front view = navController
add reveal controller to window as windows root view
the fix is
create a containing NavController
do stpes 1-3 above
add pkrevealcontroller to the containing navController
set containing nav controller nav bar to hidden
add containing nav controller to window as root view
If its navigationcontroller than you can use this inside every viewcontroller's viewdidload:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
I had the same problem, but solved very easily by just setting the UINavigationBar Y-position to 20px and not to 0px. Then you have to assign the UINavigationBarDelegate to your ViewController:
[_navigationBar setDelegate:self];
Furthermore you have to add this method to your ViewController, which will be called because of the Delegate assignment:
-(UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
return UIBarPositionTopAttached;
}
I drag out a toolbaritem in storyboard and set it on my nav controller, but when I run my code it's not there, is there something I'm missing?
EDIT:
Tried setting it in code as well in my viewDidLoad method:
UIBarButtonItem *rightBarButton = [[UIBarButtonItem alloc] initWithTitle:#"Map" style:UIBarButtonItemStyleBordered target:self action:#selector(viewMap)];
self.navigationItem.rightBarButtonItem = rightBarButton;
Won't work either.
Here's how it's set up in my storyboard:
UPDATE:
Just found my problem. In my controller code when I update it's contents I change the right bar button item for a spinner and never set it back to what it had before.
UINavigationController already has a toolbar built in. It has a property toolBarHidden which is set to YES by default, which is why it is not normally seen. If you are using storyboard you can easily make the built-in bottom toolbar visible by checking the checkbox "Shows Toolbar" in the inspector when the Navigation Controller is selected.
See the UINavigationController documentation here for more details.
EDIT:
Ok, it sounds like what you are trying to do is add a right button to your view controller's UINavigationItem. To do this in storyboard, drag a "Bar Button Item" from the Objects Library onto the Navigation Item in your ViewController. You can then set the title/style/etc of the bar button item. If nothing still shows up when you run your app, make sure that your ViewController is connected properly with a segue to the navigation controller.
Also make sure you are adding the Bar Button Item to your view controller's Navigation Item, NOT to the View Controller itself. Here is how the setup should look in your storyboard:
To add an item to a navigation bar, you need to add a Bar Button Item to the Navigation Item contained in the view controller. Go to your storyboard, find the right VC, and find the navigation item (it's in the hierarchy shown in the navigation controller 'scene'). Just drag a Bar Button Item into that hierarchy underneath the nav item, or directly onto the navbar in the visual builder display.
The navigation controller only looks at your VC's nav item when that VC is pushed onto the stack; hence modifying the VC's nav item in viewDidLoad has no effect.
(I've done this programmatically before but I don't have the code with me, so maybe I'll add that later...)
I do the following:
Create Window based application
Add UIViewController subclass
Insert Navigation Bar to the view in xib.
After I start simulator, the Navigation bar has cropped. But if I rotate the device, The navigation bar becomes normal.