UINavigationController bar covers its uiviewcontroller's content - ios

I have a UIViewController, MyViewController, with a UIToolbar at the top. Using interface builder the doc outline looks like this:
View
- subview1
- subview2
- UIToolbar
- Bar Button Item1
- Bar Button Item2
- Bar Button Item3
MyViewController is used throughout my app. Sometimes it's in a UINavigationcontroller, other times it's in a UIPopoverView.
When it appears in UINavigationController, the navigation bar covers up the UIToolbar and all other content near the top of View. In this screenshot you can see that the UIToolbar is completely covered up, and UIButton w/ an image of a green light bulb is partially covered.
According to the apple documentation
Any view that needs to be anchored to the top and just below the status bar (i.e. UIToolbar, UIButton, etc.) requires additional work for proper placement.
It proceeds to give a solution that simply uses constraints to move your VC's content down by x pixels, in my case the UIToolbar. This doesn't seem like a good solution because it assumes you always want the content moved down below the nav bar. In my case, I obviously don't since MyViewController is not always in a UINavigationController. When I use the constraint solution provided in these docs, the UIToolbar is oddly floating down x pixels unanchored from the top in all cases where MyViewController is not in a UINavigationController.
Am I missing something with how I am supposed to display a VC's content within a UINavigationController? Thanks so much.

In iOS7, UINavigationBar has translucent property and views of child VCs of UINavigationViewController are underneath UINavigationBar by default.
If you don't need this translucent effect, turn off this property by using the following code.
self.navigationController.navigationBar.translucent = NO
You can also use #ldindu's way as well.

If you are running on iOS 7.0 version then you need to set following property which is newly introduced in iOS 7.0 as follows
self.edgesForExtendedLayout = UIRectEdgeNone;
as by default edgesForExtendedLayout property is set to UIRectEdgeAll that means the view controllers use full-screen layout by default.

Identify whether you are using iOS 7.
#define IS_IOS7 [[[UIDevice currentDevice] systemVersion] hasPrefix:#"7"];
- (float)topPadding
{
return (IS_IOS7) ? 20.0f : 0.0f;
}
Use increment the Y axis of the frame by [self topPadding] to move it further down.
I hope your problem is solved.

If written in Swift, it's edgesForExtendedLayout = UIRectEdge()

Related

Ios Swift : Adding or Moving NavigationBar to bottom of the view controller

I want to move the navigation controller bar to the bottom of the view controller. How can i get this done ?
I tried :
self.navigationController!.navigationBar.frame = CGRectMake(
0,
UIScreen.mainScreen().bounds.height - 50,
UIScreen.mainScreen().bounds.width,
50)
This is moving to the bottom but hiding all other controller objects and also back button is not woking.
Sujay U N,
You should not try to move the UINavigationBar provided by the embeded UINavigationController to the bottom of the screen. Trying that will obvisoulsy move all the view's below it causing all the controller objects to hide.
Workaround
Approach 1:
Consider using ToolBar :)
Toolbar is designed to be placed at the bottom of the screen. If you are using xib or storyboard you can pick toolbar from components library and place it on your ViewController's bottom and then apply autoresizing masks or constraints properly :)
Now in order to show the back button make use of UIBarButtonItems. Change the style to custom and provide it arrow image or provide default style as done.
Though now you are all set to go :) You will notice UINavigationBar at the top of your view controller. In order to get rid of it,
select your ViewController, select its TopBar property set it to none :)
Approach 2
Use UINavigationBar.
Specific about using Navigation bar and dont want to use toolbar, well you can do the same thing with UINavigationBar as well.
Drag the UINavigationBar from components library place it at the bottom of the screen. Drag the UIBarButtonItem drop it as leftBarButtonItem, change the barButtonItem image to your back image. ( Same process as UIToolBar just use UINavigationBar instead)
Understand this is not same as the navigation bar provided by the embeded NavigationController. So get rid of NavigationBar at the top of your ViewController same as I explained above here as well
Finally,
In both the cases, draw an IBoutlet from barbutton item and handle poping the viewController programmatically.
Happy coding :)

Applying bar metrics on a standalone UINavigationBar

My app has a view controller that due to the fact it plays its own custom transition animations, provides its own standalone UINavigationBar view at the top (As opposed to using a UINavigationController).
When using an iPhone, and when rotating the device, I would like the UINavigationBar to automatically apply the landscape UIBarMetrics properties (eg, change height, change the background image, resize the buttons etc), but by default, it does not. This is a problem on iOS 7, since even if I manually change the height of the UINavigationBar, the UIBarButtonItem elements don't change their vertical positions.
Is there a way to manually 'tell' the UINavigationBar to apply specific bar metric properties to itself? Or is that actually an implementation inside UINavigationController, and not UINavigationBar?
After various testing and trial and error after asking this question, I eventually worked out a solution that fixed all of my issues, so I'll post it here under the solution I'd previously accepted.
When my app is displayed in landscape on an iPhone, I wanted the UINavigationBar at the top to shrink to the standardly accepted 32 points high, as is the case with any apps that use the UINavigationController class. However, as I am not using a UINavigationController for this particular view (for varying reasons of feasibility), I needed to implement this manually.
To account for the new transparent status bar in iOS 7, I adjusted the origin and size of the UINavigationBar so it encompassed both the bounds of the status bar, and the normal UINavigationBar region (ie, so the UINavigationBar frame origin was {0,0}, and the height was 52 points.)
Unfortunately, this happened:
While the bar itself is rendering at the proper position and height, all of the content in the bar, including the title and buttons are not positioned properly, being much too high, almost touching the status bar content.
It was pretty obvious what was happening. The navigation bar content is being vertically aligned to its own middle, completely disregarding the presence of the status bar content.
When I tested the same orientations with a normal UINavigationController, this was not the case, and the title and buttons in the UINavigationBar from the UINavigationController worked absolutely fine. Apple had done SOMETHING in there that wasn't part of the normal UINavigationBar implementation.
Going on this, I picked apart the view layout hierarchy of a UINavigationControllerto see what was happening to the UINavigationBar in there (Mainly calling a lot of NSLog() statements that would dump the subviews of the navigation bar.)
This is what I discovered:
From the looks of it, Apple have employed a relatively sneaky hack to achieve this effect. It turns out the actual UINavigationBar is actually placed right below the status bar (ie at point {0,20}) and only has a height of 32 points. Then, what happens is a private subview inside the UINavigationBar in charge of rendering the background is extended upwards, outside of the bounds of the navigation bar to encompass the region behind the status bar (ie, its origin is {0, -20}, and its height is 52 points, local to the navigation bar's subview coordinate space).
So by doing that, not only does the content vertically align properly, but the translucent effect still extends behind the status bar.
Anyway, after I discovered this, it was pretty straightforward to write a solution. All I needed to do was reposition and resize the UINavigationBar back to how I had it iOS 6 (ie, 20 points down, and only 32 points high), and then implement a UINavigationBar subclass that override the layoutSubviews method, grabbed the internal background view (Doing a quick subview check for a view with a class name that matched "Background"), and then manually extended it.
The bar metrics properties you can set on a UINavigation bar are things like background image and the title vertical position. Heigh and width need to be set from within your view controller.
If you need to manually tell the navigation bar to change it's size when the orientation changes you can implement the method - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration1 in your view controller and change the size there.
Another option you can use is to use autolayout to specify that the width of your navigation bar is pinned to the left and right sides of its superview and let it figure out how wide it should be. For example
UINavigationBar *bar = [[UINavigationBar alloc] init];
bar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bar];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bar]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[bar(44)]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];

why does Ios ignores top bar and layout items below it?

I am designing a screen using IB and in design time this is how the screen looks like:
I am using auto layout and there are no missing constraints. This is how it lookes like when I run it using the simulator:
Its a sit it has no idea there is a opaque top bar there and starts layouting the views directly from the top.
does anyone has any idea why this is happening?
Thanks
The size, status bar, orientation, top bar, bottom bar are only simulated at the attributes inspector , e.i. What u see, is NOT what u get, it's just simulate...
To make status bar/bottom bar/orientation etc. U must do it via code or .xib attributes inspector/size inspector.
For status bar, u can see this.
Hope it's help.
Add the following code to viewDidLoad in you view controller:
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
You can achieve this by implementing a new property called edgesForExtendedLayout in iOS7 SDK. Please add the following code to achieve this,
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
You need to add the above in your -(void)viewDidLoad method.
iOS 7 brings several changes to how you layout and customize the appearance of your UI. The changes in view-controller layout, tint color, and font affect all the UIKit objects in your app. In addition, enhancements to gesture recognizer APIs give you finer grained control over gesture interactions.
Using View Controllers
In iOS 7, view controllers use full-screen layout. At the same time, iOS 7 gives you more granular control over the way a view controller lays out its views. In particular, the concept of full-screen layout has been refined to let a view controller specify the layout of each edge of its view.
The wantsFullScreenLayout view controller property is deprecated in iOS 7. If you currently specify wantsFullScreenLayout = NO, the view controller may display its content at an unexpected screen location when it runs in iOS 7.
To adjust how a view controller lays out its views, UIViewController provides the following properties:
edgesForExtendedLayout
The edgesForExtendedLayout property uses the UIRectEdge type, which specifies each of a rectangle’s four edges, in addition to specifying none and all. Use edgesForExtendedLayout to specify which edges of a view should be extended, regardless of bar translucency. By default, the value of this property is UIRectEdgeAll.
extendedLayoutIncludesOpaqueBars
If your design uses opaque bars, refine edgesForExtendedLayout by also setting the extendedLayoutIncludesOpaqueBars property to NO. (The default value of extendedLayoutIncludesOpaqueBars is NO.)
automaticallyAdjustsScrollViewInsets
If you don’t want a scroll view’s content insets to be automatically adjusted, set automaticallyAdjustsScrollViewInsets to NO. (The default value of automaticallyAdjustsScrollViewInsets is YES.)
topLayoutGuide, bottomLayoutGuide
The topLayoutGuide and bottomLayoutGuide properties indicate the location of the top or bottom bar edges in a view controller’s view. If bars should overlap the top or bottom of a view, you can use Interface Builder to position the view relative to the bar by creating constraints to the bottom of topLayoutGuide or to the top of bottomLayoutGuide. (If no bars should overlap the view, the bottom of topLayoutGuide is the same as the top of the view and the top of bottomLayoutGuide is the same as the bottom of the view.) Both properties are lazily created when requested.

UINavigationBar clips top content

I have added a custom titleView to my UINavigationItem, and that contains a view that is intended to be under the status bar. It looks fine, and when I push another viewcontroller and that transitions away in the standard right-to-left animation it looks fine. However, when I [self.navigationController popViewControllerAnimated:YES] it clips the top of this view until the animation is finished. Please see attached image for a better explanation of the problem.
It's only until after the pop-animation is done that it looks normal again. I have tried everything I can think of. Setting cropsToBounds to NO on all the views the viewController AND navigationBar. I've tried also layer.masksToBounds and just about every property that sounds familiar. I've added a timer that prints the frame rectangle of the navigationBar and the custom titleView and it doesn't appear that they change anything.
Does anybody know what I'm doing wrong?
Two ways to do it :
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) { // if iOS 7
self.edgesForExtendedLayout = UIRectEdgeNone; //layout adjustements
}
Or
You need to set Delta of your view controller. Switch Story board to ios6.1 or later from utility area (1st item). Then select view of your Vc and in size inspector menu in utility area there will be delta section below frame. There will be triangle before every delta. Triangle y to 64 (you should be on ios6.1 or later of your storyboard).
If you need help on Deltas visit : Interface Builder: What are the UIView's Layout iOS 6/7 Deltas for?

Popover with UINavigationController/UITableViewController cropping nav bar

I've implemented a Popover that is composed of a UINavigationController that has a UITableViewController embedded. When the popover comes up, the navigation bar is cropped on the top and sides. I've attempted to use solutions I've read here with forcing the size - setting it to CGRectMake(0,0) then to the right size on ViewWillAppear and ViewDidAppear but it has no effect. The UINavigationController and UITableViewController have Size as Freeform in the Simulated Metrics (although I've tried Inferred, to no avail as well). I've tried setting the popover size to an explicit size, still no go. It ignores all of my attempts to make it look right.
What is the key to making a popover look good with a dynamic TableView?
TIA!
I've resolved this problem. I removed embedding of the UITableViewController in a UINavigationController and instead added a UINavigationBar to the header of the UITableView. The view appears correctly now with correct sizing of the navigation bar and buttons.

Resources