iOS MapView goes under navigation bar, status bar, and tab bar controller - ios

I have a ViewController with a navigation controller and a tab bar controller. This ViewController has 2 buttons that toggle the visibility of a scroll view and a map view. The main thing is to have these 2 buttons always show up in the same place regardless of orientation or the view that happens to be visible.
The problem I am having is that the MapView won't size properly. If I just give it a frame from self.view.bounds it goes under the navigation bar / tab bar - basically taking up the whole screen. This throws off the location of my toggle buttons.
I noticed my ScrollView does the same (using a background color and a translucent navigation bar) but the positioning of sub views on it stay within the visible area (between the navigation bar and the tab bar). So when I add my toggle buttons, they show in the correct place.
When I press the toggle buttons, I just re-assign the parent view of the buttons to the now displayed view (ScrollView or MapView). This always works on the scroll view but due to the positioning, they end up going under the navigation bar when the MapView is displayed.
I have tried creating the frame for the MapView manually but I get odd results. I use this for the frame:
CGRect mapFrame = CGRectMake(
0,
(self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height),
self.view.frame.size.width,
(
self.view.frame.size.height
- (self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height + self.tabBarController.tabBar.frame.size.height)
)
);
I then set the auto resizing masks
[self.mapView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin];
But with this, if I enter into the view controller in landscape mode - the MapView is off the screen. If I enter in portrait mode and then rotate to landscape, the top margin is off but about 10 points so it still goes under the navigation bar a bit (and has a visible margin between the tab bar and the bottom of the map view).
How can I make the MapView subviews only display within the visible region like the ScrollView does? I don't mind so much if the map itself goes under the navigation bar / tab bar

Ugh, I found the answer just a few minutes ago. I have no idea why this is the default behavior on iOS 7 but alas, there it is.
The solution is to add this to the viewDidLoad on the ViewController
[self setEdgesForExtendedLayout:UIRectEdgeNone];
[self setAutomaticallyAdjustsScrollViewInsets:NO];
Much thanks to the post here

Related

Set image view underneath the navigation bar

In my UIViewController I have UIImageView that takes up the full size of the controller (screen) and serves as a background. On top of UIImageView I have a UITableView with a clear background. I set the navigation bar to translucent like this:
self.navigationController.navigationBar.translucent = YES;
UIImageView is underneath the navigation bar as I want it to be. Unfortunately the same happens to UITableView. I want to put UITableView at the bottom of navigation bar, leaving UIImageView underneath. If I set:
[self setEdgesForExtendedLayout:UIRectEdgeBottom]
then UITableView is at the bottom of the navigation bar, but the same happens also to UIImageView. What would be the easiest solution to leave UIImageView underneath the navigation bar and push down the UITableView at the bottom of the navigation bar?
By default in iOS 7 the content extends to the top and bottom of the screen, underneath any navigation bars, tool bars, or tab bars. If you were to set the frame of the table view to be start after the navigation bar, the content of the table view would not scroll beneath the navigation bar providing the nice blur effect.
What you'll probably want to do instead, is keep the y origin of your table view at 0, underneath the navigation bar, and set the content inset so the content starts after the navigation bar.
This is pretty simple. If you're using auto layout the top layout guide of the view controller will recognise the height of the status bar and navigation bar so you don't need to calculate this yourself. The bottom of the navigation bar should end at 66.
//Using Auto Layout
CGFloat navigationBarHeight = self.topLayoutGuide.length;
//Not using Auto Layout
UINavigationBar *nav = self.navigationController.navigationBar;
CGFloat navigationBarHeight = nav.frame.origin.y + nav.frame.size.height;
myTableView.contentInset = UIEdgeInsetsMake(navigationBarHeight, 0, 0, 0)
And of course if you actually do want the frame to start after the navigation bar the height above stays the same, you just need to manually set the frame of the table view.
CGRect tableViewFrame = self.view.bounds;
tableViewFrame.origin = CGPointMake(tableViewFrame.origin.x, navigationBarHeight);
tableViewFrame.size = CGSizeMake(tableViewFrame.size.width, tableViewFrame.size.height - navigationBarHeight*2);
myTableView.frame = tableViewFrame;
EDIT: Ah, almost forgot. You'll also want to change the scrollIndicatorInsets to match the contentInset, so your scroll bars don't move offscreen.
myTableView.scrollIndicatorInsets = myTableView.contentInset;

In iOS 7, how to scroll to the top of a UIScrollView when using a translucent UINavigationBar?

In iOS 6, you could scroll to the top of a UIScrollView using:
[scrollView setContentOffset:CGPointZero animated:YES];
If you use that code in iOS 7 with a translucent navigation bar, you get a result that is technically correct, but not user friendly. The top of the scroll view will be positioned to the origin of the screen.
How would I position the top of the scroll view to the bottom of the navigation bar instead? I'm looking for a solution that is not hardcoded, because in my application, sometimes the status bar and navigation bar can be hidden. Also, I would like to keep the translucent effect instead of copping out and doing self.edgesForExtendedLayout = UIRectEdgeNone.
Instead of using hard-coded values, use the new API:
[self.scrollView setContentInset:UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0)];
You are setting the content insets of the scroll view to top and bottom layout guides. So if you have a navigation bar that is 44 points and a status bar of 20 points and no status bar, it will be 64 points top (in portrait) and 0 points bottom.
You should do this in viewDidLayoutSubviews.
You have to use this method -> setContentOffset:animated:
[_scrollView setContentOffset:CGPointZero animated:YES];
Just use -60 for the y coordinate or, better yet, get the statusbar and navigation bar heights dynamically because they both change.
See UIApplication's statusBarFrame and self.navigationController.navigationBar.bounds, I think.

iOS 7 status bar transparent

In storyboard, in a view controller I tried add a navigation bar under the status bar, running it, it is transparent and shows a label that's supposed to be blurred, like by navigation bar.
But when placing the same view controller embedded in a navigation view controller, the underneath background image could be blurred, which is my intention.
What are these two way different results? What need to do for the firs method to make status bar blur?
Thanks!
In iOS 7 the status bar is transparent by default. The blurring you're seeing when there's also a navigation bar is actually created by the navigation bar. So to create the effect you're looking for without a navigation bar, you need to position a view that produces a blurring effect beneath the status bar.
For reference, add your view with a frame provided by:
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
I know this is old, just for reference, I solved this by setting self.navigationController.navigationBar.clipToBounds = NO
I haven't tested this completely, but go to your plist file and check the following settings:
"View controller-based status bar appearance": If this is set to "Yes", then it should display a status bar that is unique to each View Controller, which might be what you need.
"Status bar style": You may set this to three different styles: Opaque black, Gray, and Transparent black.
Let me know if this worked for you.
UINavigationController will alter the height of its UINavigationBar to either 44 points or 64 points, depending on a rather strange and undocumented set of constraints. If the UINavigationController detects that the top of its view’s frame is visually contiguous with its UIWindow’s top, then it draws its navigation bar with a height of 64 points. If its view’s top is not contiguous with the UIWindow’s top (even if off by only one point), then it draws its navigation bar in the “traditional” way with a height of 44 points. This logic is performed by UINavigationController even if it is several children down inside the view controller hierarchy of your application. There is no way to prevent this behavior.
It looks like you are positioning your view hierarchy in the first example starting at the point (0,20). Also, is that a UIToolbar or a UINavigationBar? If it's the latter, why are you using it by itself and not using it inside of UINavigationController?
If you do not use UINavigationController and are instead using custom view controller containers, you'll need to position your views accordingly.
See this answer for a thorough explanation.
I have similar UI design and based on Matt Hall answer and some article I've googled, I come up with something like this:
- (void)viewDidLoad {
[super viewDidLoad];
if (NSFoundationVersionNumber>NSFoundationVersionNumber_iOS_6_1) {
CGRect statusBarFrame = [self.view convertRect: [UIApplication sharedApplication].statusBarFrame fromView: nil];
UIToolbar *statusBarBackground = [[UIToolbar alloc] initWithFrame: statusBarFrame];
statusBarBackground.barStyle = self.navBar.barStyle;
statusBarBackground.translucent = self.navBar.translucent;
statusBarBackground.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
[self.view addSubview: statusBarBackground];
}
}
Where self.navBar points to navigation bar added in storyboard. This is needed only in case when it runs on iOS7 that is why I've added this condition (my app has to support iOS5).
This works like a charm.
alternative approach (enforce status bar size) is also good:
- (void)viewDidLoad {
[super viewDidLoad];
if (NSFoundationVersionNumber>NSFoundationVersionNumber_iOS_6_1) {
CGRect statusBarFrame = [self.view convertRect: [UIApplication sharedApplication].statusBarFrame fromView: nil];
self.navBar.frame = CGRectUnion(statusBarFrame, self.navBar.frame);
}
}
I've found another solution I think this is best since it involve only storyboard and no code is required.
Switch storyboard view to 6.1 mode (view as: iOS 6.1 and Earlier)
Select problematic UINavigationBar
in size section add 20 delta height in "iOS6/7 Deltas"
Switch back view to 7.0 mode (view as: iOS 7.0 and Later), and be happy with result.
when you embed view controller with navigation view controller that time you will see navigation bar to all the view controller you are pushing to from same view controller. In your first case you are adding the navigation bar object, insted of that you can select view controller from storyboard , go to attributes inspector tab & from their select Top bar as translucent navigation bar.

Image view hide navigation bar in scroll view

In my ipad app, there is one navigation bar and one image view within scroll view.
When i run my app, the image view hide the navigation bar.
So, i remove image view and run again, then i see navigation bar.
But, i can't click the button in navigation bar.
Please, tell me how can i solve it?
Keep in mined the hierarchy of the view , if the UIScrollView is on top of the views , then any view behinde it will not receive any touch event.
The navigation bar added with XIB is a part of the subviews in you main view so you have to start the UIScrollView under the navigation bar , y = 44
ScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 44, self.view.frame.size.width,self.view.frame.size.height-44)];
and do not forget to subtract 44 from the ScrollView height to fit the screen.

ios changing navigation bar height causes leftBarButtonItem not to be centered

I'm working on a project that needs to have the navigation bar height bigger than the default.
This is how i set the nav bar height:
- (CGSize)sizeThatFits:(CGSize)size {
if (iPad) {
CGSize newSize = CGSizeMake(768,86);
return newSize;
}
return CGSizeMake(320, 44);}
I set an bg image for the navigation bar and that's working ok.
The problem is that the back button and the right button item are not centered.
Does anyone know how to center them?
Thanks
It's generally bad practice to manipulate the navigation bar's height. I tried to do it a number of different ways for one project and every approach had a "gotcha". Namely, the navigation buttons are always justified to the bottom of the navigation bar, so adjusting it's height will cause the buttons to look like they're rendering towards the bottom of the bar. And the buttons will animate oddly as you push and pop other controllers. I would suggest not adjusting the height of the navigation bar.

Resources