UINavigationController's view and 20 points offset - ios

This is an already posted question but I need to understand what is going on with the following scenario. I'm developing an iPad application and I created a UINavigationController like the following (test purposes).
UINavigationController* navigationController = [[UINavigationController alloc] init];
navigationController.view.backgroundColor = [UIColor redColor];
Once created, I added the UINavigationController's view as a subview of a UIViewController.
[self.view addSubview:navigationController.view];
The result is displayed in the following image:
As you can see, there is a gap between the status bar and the navigation bar of the UINavigationController. Since the view of the UINavigationController is red, it seems that the frame of the navigation bar has that gap.
I've found an hack to fix the problem. By setting the frame for the UINavigationController, the navigation bar goes in the right position.
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect frameRect = CGRectMake(navigationController.view.frame.origin.x, navigationController.view.frame.origin.y - statusBarFrame.size.height, navigationController.view.frame.size.width, navigationController.view.frame.size.height);
navigationController.view.frame = frameRect;
Now, since I don't like very much that hack and I would understand what is going on, do you have any suggestions to find an elegant solution to resolve the problem?
Thank you in advance.

That 20px offset is for status bar, navigation controller is designed to be full-screen, but you are adding it to the subview of the main view.

viewController setWantsFullScreenLayout:YES
It may help you.

This is the fix that really solved all the problem. So thought of posting it as it might really.
How this works
This gonna set my navigation bar origin to 0, and in turn the view of navigation is also set to 0 which takes the reference of Navigation Bar, which solves all the mess :)
And 44 is the heigh of Navigation Bar in the code. :)
Put the code in ViewDidAppear,
CGRect windowFrame = [UIScreen mainScreen].applicationFrame;
//Setting the Origin to 0 of both Navigation Bar and Navigation View for Both Landscape and Portrait
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)){
[self.navigationController.navigationBar setFrame:CGRectMake(0, 0, windowFrame.size.width, 44)];
[self.navigationController.view setFrame:CGRectMake(0, 0, windowFrame.size.width, windowFrame.size.height)];
}
else{
[self.navigationController.navigationBar setFrame:CGRectMake(0, 0, windowFrame.size.height, 44)];
[self.navigationController.view setFrame:CGRectMake(0, 0, windowFrame.size.height, windowFrame.size.width)];
}

[self setWantsFullScreenLayout:<#(BOOL)#>];
is deprecated. If you want to add subviews to your ViewController without worrying about NevigationBar use:
self.edgesForExtendedLayout = UIRectEdgeNone;

Related

iOS hidesBarsOnSwipe status bar background color

When I swipe and hide the navigation bar with the hidesBarsOnSwipe property the status bar has a clear background. How can I set the background of the status bar to the same color as the navigation bar? Here are a few pictures showing my problem, this is all contained in a UITableViewController.
Separate
Separate picture, looks like one big one.
I've come across the same issue, and was able to solve it. I'm fairly new to iOS dev, and I don't imagine this solution to be foolproof. I couldn't find any good answers elsewhere, so here's how I overcame it:
I converted from a UITableViewController over to UIViewController with a nested UITableView. Note, double check that the delegate to the child tableview is set to the UIViewController.
I Added a view with a height of 20px and a background colour that you want to set as the "background" to the status bar. Set the constraints on that view as follows:
On your table view, set the constrains to be basically full screen. One important note here, the top constraint is to "Top Layout Guide.Top" and not to "Top Layout Guide.Bottom". By default I believe this constraint ties to the bottom. Double clicking on the constraint allows you to adjust it to the top. Without this, any table header cells weren't positioned properly for me
Hope that helps.
Adding to George Huber's answer. I solved this issue programmatically by adding a 20pt height UIView as a subview of the navigationController's view property -- in viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *statusBarBG = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 20)];
statusBarBG.backgroundColor = [UIColor navBar];
[self.navigationController.view addSubview:statusBarBG];
// REST OF CODE
}
Per skg's answer, I add a relative height for status bar according to iOS version.
self.navigationController.hidesBarsOnSwipe = true;
// add a UIView as subView to navigationController
CGFloat statusBarHeight;
if (#available(iOS 13, *)) {
NSArray *windows = UIApplication.sharedApplication.windows;
UIWindow *keyWindow = nil;
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
keyWindow = window;
break;
}
}
statusBarHeight = keyWindow.windowScene.statusBarManager.statusBarFrame.size.height;
NSLog(#"statusBarHeight: %f", statusBarHeight);
} else {
statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
}
UIView *statusBarBG = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), statusBarHeight)];
statusBarBG.backgroundColor = [UIColor systemBackgroundColor];
[self.navigationController.view addSubview:statusBarBG];

Custom view controller presentation causes the navigation bar to bounce

I'm presenting a view controller using the transitioning delegate modally from my root view controller.
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
UIViewController *rootVC = [window rootViewController];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:authVC];
navController.modalPresentationStyle = UIModalPresentationCustom;
navController.navigationBar.translucent = NO;
navController.transitioningDelegate = self;
[rootVC presentViewController:navController animated:YES completion:nil];
My transitioning delegate adds the view as follows, where authorizationVC is the login view pictured in the screenshots.
UIView *containerView = [transitionContext containerView];
[containerView addSubview:blurredView];
[containerView insertSubview:_authorizationVC.view aboveSubview:blurredView];
_authorizationVC.view.frame = CGRectMake(10, 30, 300, 450);
At first, the view animates in, and the navigation bar is full height, what I believe to be 64 pixels (44 for the nav bar and 20 for the status bar).
As soon as my animation completes, the nav bar shrinks to 44 pixels. The transition is jarring. The content inside my view controller is unaffected.
How do I avoid this jittering navigation bar? The second image is what I'd like to achieve.
Set all the properties of the view before adding it to its superview.
UIView *containerView = [transitionContext containerView];
_authorizationVC.view.frame = CGRectMake(10, 30, 300, 450); /// Change the frame FIRST!
[containerView addSubview:blurredView];
[containerView insertSubview:_authorizationVC.view aboveSubview:blurredView];
Voila! The nav bar acts as expected.
I would avoid using a UINavigationController if you don't really need it.
The UINavigationController takes into account the topLayoutGuide in the way it sizes the navigation bar. If you just want the coloured bar and close button, I'd simplify it and use your own views for that.
If you must use a UINavigationController you could try playing with the status bar's appearance and see how it affects the navigation controller's presentation.

Adding MKMapView Causes Status Bar Issue in iOS 7

I'm solving the status bar issue in iOS 7 using
if(st.version == 7)
{
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = self.navigationController.view.frame;
frame.origin.y = 20;
frame.size.height = screen.size.height - 20;
self.navigationController.view.frame = frame;
}
Since I'm using navigation controller and pushing from one to another using [self.navigationController pushViewController:newone animated:YES];. It works fine in all view controllers. But, if the viewcontroller has mkmapview in xib, status bar issue of ios 7 occurs.
If I delete the mapview form xib and push to that view controller means, it will be like,
If I add the mapview even by code below,
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 100, 320, 100)];
[self.view addSubview:self.mapView];
It looks like,
How to solve this?
if(st.version == 7){
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 120, 320, 100)];
}else{
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 100, 320, 100)];
}
If you add mapView in viewWillAppear replace it in viewDidAppear.
Maybe you have this issue because you're doing manipulations with view's frames before your view is completely set up
I would highly suggest against doing it like that.
If you're using interface builder, then add constraints based on how you want your application to look and the frame will auto adjust itself.
If you're not using interface builder, then still use constraints, but get a good tutorial about making constraints programatically (as I don't know how to do it myself).
Edit: The reason I HIGHLY suggest not doing it with hardcoded numbers is that it'll be a pain to do iOS 6/7 Landscape/Portrait 3.5/4 inch screens. That's 8 cases.
i think you have some adjust your navigation Y position set -20px. that way it goes overlay. use this code your ViewController
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = self.navigationController.view.frame;
frame.origin.y =0;
frame.size.height = screen.size.height;
self.navigationController.view.frame = frame;
or may it you have use wantFullScreenLayout some where in your project
setWantsFullScreenLayout = YES:
statusbar section is located to the (0,0) point to catch.
Statusbar and as large as the size of the current view to increase the value of mainScreen change the size of the bounds.
Statusbar change the style of the translucent style.
this below link you get some clear idea about your issue
How do I get the navigation bar in a UINavigationController to update its position when the status bar is hidden?
Override the -edgesForExtendedLayout method in your view controller
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;
}
If you want to hide status bar from a particular view add this method in that particular view.m file
- (BOOL)prefersStatusBarHidden
{
return YES;
}
What about setting self.automaticallyAdjustsScrollViewInsets = NO; in viewDidLoad of your view controller or in IB?
Try to set MapView(ScrollView) automaticallyAdjustsScrollViewInsets = NO;
Try to set edgesForExtendedLayout to UIRectEdgeNone;
Try to use UIViewController.topLayoutGuide, see the Q&A from apple about this issue:Preventing the Status Bar from Covering Your Views.
Try to use the bar position delegation, see UIBarPositioningDelegate Protocol Reference
According to your description and screenshots, you are trying to move the whole UINavigationController.view.frame 20 pt, and the MapView(ScrollView) did something to prevent it happened (or re-set), put some breakpoint and log to track the frame of UINavigationController.view.frame changed.
Could you please provide a sample project? I'm so curious about what really happened.
try this
- (void)viewWillAppear:(BOOL)animated
{
self.navigationController.navigationBar.translucent = NO;
}
- (void)viewDidAppear:(BOOL)animated
{
self.navigationController.navigationBar.translucent = YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[application setStatusBarHidden:YES];
return YES;}
Please add this line to your code.This will hide the status bar from your app.
If you have a xib. Did you try to enabled Top Bar in simulated Metrics ?

Solve the viewController sizing mystery! Why do elements (UIImageView and Nav bar) change size when switching viewControllers?

So this is the code for my mapView:
self.mapView = [[MKMapView alloc] init];
self.mapView.frame = CGRectMake(0, 70 , self.view.bounds.size.width,
self.view.bounds.size.height);
When I push to this view controller from one viewcontroller it looks just fine. The navigation bar and map view are all in the correct spot; however, when I tried to create a button that go directly to the map Viewcontroller from ANOTHER viewController everything changed.
The map view has shrunk and the navigation bar is missing now..? Here's the new button from the other ViewController:
UIImage* image4 = [UIImage imageNamed:#"Near_me_carousel.png"];
_mapButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 18, 26, 26)];
[_mapButton setBackgroundImage:image4 forState:UIControlStateNormal];
[_mapButton addTarget:self action:#selector(MapButton)
forControlEvents:UIControlEventTouchUpInside];
[_mapButton setShowsTouchWhenHighlighted:YES];
[self.view addSubview:_mapButton];
Here's the method:
-(void) MapButton {
MapViewController *mapView = [[MapViewController alloc] init];
[self.navigationController presentViewController:mapView animated:YES completion:NULL];
}
I'm so confused as to why this is happening! Any ideas?
I don't know if this is really your problem, but here's a shot:
Inside your button method, you are calling your MapViewController modally. If the viewController itself does not have a UINavigationBar, of course it will not be displayed.
When you have a push transition, through a UINavigationController, a navigationBar is automatically added above of your view.
And here's the tricky part: when presented as a push transition, the 0 y value of the view's frame is the point just below the navigationBar. I. e., the navigationBar does not belong to your view.
And when presented through a modal transition (presentViewController:), the 0 y value is the top/left point of the window, even if you add a NavigationBar yourself.
Ilustrating:
The origin of it will be here if presented as a modal:
And here if presented if a push in a navigation stack:
Conclusion:
So, in your case, the y-value 70 in this code
self.mapView.frame = CGRectMake(0, 70 , self.view.bounds.size.width,
self.view.bounds.size.height);
will be different according to the transition style. In a modal, it will look like it's displaced 44 points to the top (size of the navigation bar)

UITabBarController not responding

I'm using a UITabBarController with UINavigationControllers like this
I add this to the view using
tabctrl.view.frame = CGRectMake(0, 0, 320, 548);
[self.view addSubview:tabctrl.view];
The screen looks like
But I can't switch to other tab(ie, touching on tabctrl's tab has no response)
If I change the frame like
tabctrl.view.frame = CGRectMake(0, 0, 320, 488);
then the screen looks like,
Now, I can touch the tab and switch to required viewcontroller. How to solve this issue?
I need to get access to the tabctrl when its frame height is 568.
I'm using xcode 4.6.2 and ios simulator 4inch retina.
Use this code:
[appDelegate.window setRootViewController:tabctrl];
rather than:
tabctrl.view.frame = CGRectMake(0, 0, 320, 568);
[self.view addSubview:tabctrl.view];
Your tabbar controller might be behind something else on the bottom of the screen. You can test it with code:
[self.view bringSubviewToFront: tabctrl]
If this fixes your problem, try to find which view is in front of your tabbar controller
Set your rootViewController's wantsFullScreenLayout property to YES
tabbarController.wantsFullScreenLayout = YES
This should solve your tabbar switching issue on 4-inch screen

Resources