ios7 UINavigationBar stops extending under status bar after a while - iphone

First of all - this is NOT a question about navigation bar overlapping status bar (as many others).
UINavigationBar (of my navigation controller) is perfectly aligned as I want.
The problem is with my navigation bar custom background.
Background image (or navigation bar itself) stops expending under status bar randomly (after few seconds after my application starts or when I present / dismiss modal navigation controllers over it).
My custom image has proper dimensions for iOS (640x128px).
1. Initial look (desired - custom 640x128px background extends nicely under status bar):
2. After a while (flickers by itself):
What could cause such random flickering of UINavigationBar background image?
I use following code to configure my background:
// Load resources for iOS 7 or later
[[CustomNavigationBar appearance] setBackgroundImage:[self imageNamed:#"bg_top_ios7.png"] forBarMetrics:UIBarMetricsDefault];
[[CustomNavigationBar appearance] setBackgroundImage:[self imageNamed:#"bg_top_ios7.png"] forBarMetrics:UIBarMetricsDefaultPrompt];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
My status bar settings in the Info.plist file:
I have also following settings in my UIViewController subclass init method (not sure if it matters):
-(id)init{
//DLog(#"BaseViewController init...");
if (self = [super init]) {
popToRoot = modal = NO;
rootIndex = 0;
indexInBottomNavigation = 0;
[Crashlytics setObjectValue:#"init" forKey:NSStringFromClass([self class])];
// iOS 7 adoptions:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
if ([self respondsToSelector:#selector(extendedLayoutIncludesOpaqueBars)])
self.extendedLayoutIncludesOpaqueBars = YES;
if ([self respondsToSelector:#selector(automaticallyAdjustsScrollViewInsets)])
self.automaticallyAdjustsScrollViewInsets = NO;
}
return self;
}
My view controllers are embedded in UINavigationController (which takes care of UINavigatioBbar positioning).
I am also using ECSlidingViewController (reveal container) as a container for my navigation controllers but I am not sure if it matters.

It turned out I was changing clipsToBounds = YES of navigation controller's navigation bar (somewhere in the app):
navigationController.navigationBar.clipsToBounds = YES;
In order for UINavigationBar to extend its background under status bar
its clipsToBounds must be set to NO (which is the default).
Make sure you do not mock around with it.
Solution simple as:
navigationController.navigationBar.clipsToBounds = NO;

Related

NavigationBar hides TableView in TabBarViewController

I have a ViewController that Pushes a TabBarViewController. Inside that TabBar View Controller I have 4 tabs. Two of these tab bars are UITableViewControllers and the other two are ViewControllers. The first tab is a table view controller and is working fine, ie not being hidden by the navigation bar. The third tab, which is another TableViewController, is being partially covered by the navigation bar. The first section and first cell is being hidden underneath the navigation bar. Has anyone had this problem in the past or does anyone know a solution to this? I've tried a couple of things like resizing the frame size manually
self.tableView.frame = CGRectMake(10,10,self.view.bounds.size.width -20, self.view.bounds.size.height-20);
That did't seem to work. I tried AutoLayout as well and didn't work. I don't know what else to do. Anyone have any suggestions or ideas of how to tackle this.
Edit: I've tried the edgesForExtendedLayout but it is making my navigationbar a darker color. It animates the color change in the navigationbar, sort of like a loading bar.
Note: This is only happening in ios7. I just simulated it in iOS 6.1 and the navigationbar does not cover the table view controller at all, which is weird to me. Any one have any suggestions?
Edit #2: Noticing that this is an iOS 7 > problem i did the following but now the navigation bar has changed color to a darker color.
if([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."][0] intValue] >= 7)
{
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
{
self.edgesForExtendedLayout = UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
}
}
In the viewDidLoad method of UITableViewController (assuming it's loaded with a call to the tabBarController) that is associated with the tabs use
if ([self respondsToSelector:#selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
self.tableView.contentInset = UIEdgeInsetsMake(0., 0., CGRectGetHeight(self.tabBarController.tabBar.frame), 0);
}
I fixed that with:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)]) {
viewcontroller.edgesForExtendedLayout = UIRectEdgeNone;
viewcontroller.extendedLayoutIncludesOpaqueBars = NO;
viewcontroller.automaticallyAdjustsScrollViewInsets = NO;
}

Enable/disable statusBar per view on iPhone (20 px issue)

I just want to enable/disable the status bar per view controller (some view full screen, some not)
I've been several times through all the post related to the status bar 20 pixels issue, but still have the problem, especially on iOS5.0 (some trick worked on older iOS version):
Here is the problem definition:
I use [[UIApplication sharedApplication] setStatusBarHidden:YES] to hide the status bar
I always have the 20 pixel height white empty area if I do this
I've try to enable/disable the navigation bar to force a layout, this does not works on iOS 5:
[self.navigationController setNavigationBarHidden:NO animated:NO];
[self.navigationController setNavigationBarHidden:YES animated:NO];
I've try to manually reset the view frame size, no change
self.view.frame=CGRectMake(0, 0, 320, 480);
I've tried to change manually the navigation container view:
self.navigationController.frame=CGRectMake(0, 0, 320, 480);
All the view are of course 480 pixels height
Use the following method in viewWillAppear of view controller to which you would like to display StatusBar.
[[UIApplication sharedApplication]setStatusBarHidden:YES];
Declare one BOOL variable to indicate whether status bar is hidden or not while view is loaded in view controller which you would like to hide status bar and set its value to NO.
BOOL statusBarHidden = NO;
Then add the following code in viewWillAppear of view controller(Status Bar is hidden in this view)
[[UIApplication sharedApplication] setStatusBarHidden:YES];
if(statusBarHidden == NO)
{
self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -20.0);
statusBarHidden = YES;
}
I think, You want to hide Status Bar andSet the ViewControllers In Full Screen With Navigation Bar then use
[self.navigationController.view setNeedsLayout];
other method use in you want to hide status Bar....
[[UIApplication sharedApplication]setStatusBarHidden:YES withAnimation:NO];
[self wantsFullScreenLayout];

Add Text in Statusbar [iOS Cydia App] [duplicate]

Is it possible to add a UIView on the staus bar of size (320 x 20)? I don't want to hide the status bar, I only want to add it on top of the status bar.
You can easily accomplish this by creating your own window above the existing status bar.
Just create a simple subclass of UIWindow with the following override of initWithFrame:
#interface ACStatusBarOverlayWindow : UIWindow {
}
#end
#implementation ACStatusBarOverlayWindow
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Place the window on the correct level and position
self.windowLevel = UIWindowLevelStatusBar+1.0f;
self.frame = [[UIApplication sharedApplication] statusBarFrame];
// Create an image view with an image to make it look like a status bar.
UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:self.frame];
backgroundImageView.image = [UIImage imageNamed:#"statusBarBackground.png"];
[self addSubview:backgroundImageView];
[backgroundImageView release];
// TODO: Insert subviews (labels, imageViews, etc...)
}
return self;
}
#end
You can now, for example in a view controller in your application, create an instance of your new class and make it visible.
overlayWindow = [[ACStatusBarOverlayWindow alloc] initWithFrame:CGRectZero];
overlayWindow.hidden = NO;
Be aware of messing with the window key status by using - (void)makeKeyAndVisible or similar. If you make your main window (the UIWindow in your Application Delegate) loose key status, you will encounter problems with scrolling scrollviews to top when tapping the status bar etc.
I wrote a static library mimicing Reeders status bar overlay, you can find it here: https://github.com/myell0w/MTStatusBarOverlay
It currently supports iPhone and iPad, default and opaque black status bar styles, rotation, 3 different anymation modes, history-tracking and lots of more goodies!
Feel free to use it or send me a Pull Request to enhance it!
All answers looks like working, but in iOS6.0 I have next problems:
1/ Rotations looks bad
2/ Window (status bar is kind of Window) needed rootViewController
I'm using answer from myell0w, but rotate works not good. I've just remove one extra window and using UIWindow from AppDelegate to implement status bar.
May be this solution is ok only for one UIViewController-app...
Ive implemented by the next way:
1/ In ApplicationDelegate:
self.window.windowLevel = UIWindowLevelStatusBar + 1;
self.window.backgroundColor = [UIColor clearColor];
self.window.rootViewController = _journalController;
2/ Create custom UIView and implement all that you need inside:
For an example touchable statusbar:
#interface LoadingStatusBar : UIControl
And easily create and add to your controller view:
_loadingBar = [[LoadingStatusBar alloc] initWithFrame:topFrame];
[self addSubview:_loadingBar];
3/ Some magic when add your controller view (in initWithFrame:)
CGRect mainFrame = self.bounds;
mainFrame.origin.y = 20;
self.bounds = mainFrame;
Your controller view will has 2 views - content view and status bar view. You can show status bar, or hide it when you want.
Frame of content view will be:
_contentView.frame = CGRectMake(0, 20, self.bounds.size.width, self.bounds.size.height);
4/ And one last magic here :)
To detect touches in non touchable area I've used:
-(id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (point.y < 20) return _loadingBar;
return [super hitTest:point withEvent:event];
}
For now it works fine on iPad/iPhone and all iOS's from 4 to 6.
Just to dismiss the "You cannot do this comments"...
I don't know how but I know it is doable. The Feed reader app called Reeder does that.
As you can see from the screenshot, Reeder puts a small dot on the top right of the screen. When you tap it. The bar will fill the whole statusbar until you tap it again to make it small.
First of all, a big thank you to #Martin Alléus for providing the code for this implementation.
I'm just posting for a problem that I faced and the solution I used, as I believe others might experience the same issue.
If the App is started while an call is in place, the status bar height will be 40 pixels and this means that the custom status bar will be initialized with that height.
But if the call is ended while you are still in the app, the status bar height will remain still 40 pixels and it will look weird.
So the solution is simple: I've used the Notification center to subscribe to the status bar frame change delegate of the app and adjust the frame:
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame {
//an in call toggle was done
//fire notification
[[NSNotificationCenter defaultCenter] postNotificationName:kStatusBarChangedNotification object:[NSValue valueWithCGRect:oldStatusBarFrame]];
}
And in the ACStatusBarOverlayWindow we subscribe to the notification:
-(id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
// Place the window on the correct level & position
self.windowLevel = UIWindowLevelStatusBar + 1.0f;
self.frame = [UIApplication sharedApplication].statusBarFrame;
self.backgroundColor = [UIColor blackColor];
//add notification observer for in call status bar toggling
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(statusBarChanged:) name:kStatusBarChangedNotification object:nil];
}
return self;
}
and our code to adjust the frame:
- (void)statusBarChanged:(NSNotification*)notification {
//adjust frame...
self.frame = [UIApplication sharedApplication].statusBarFrame;
//you should adjust also the other controls you added here
}
The kStatusBarChangedNotification is just a constant I've used for easy referrence, you can simply replace it with a string, or declare the constant globally.

How to make a view which covers whe whole screen, including the status bar?

I want to make an overlay which is partially transparent, and covers the entire screen including the status bar. I've seen that the folks at tapbots do exactly that. So it must be possible somehow. Status bar should still be visible!
Before iPhoneOS 3.2:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
after iPhoneOS 3.2:
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationNone];
For more information on these, see the documentation for UIApplication.
There are two ways to hide the status bar:
Programaticaly at runtime by using UIApplication sharedApplication:
- (void)setStatusBarHidden:(BOOL)hiddenwithAnimation:(UIStatusBarAnimation_)animation
Or at design time using the Info.plist property UIStatusBarHidden yes/no value.
You could try creating a full-size view and adding it as a subview of your main window. Something like:
CGRect mainWindowSize = [UIScreen mainScreen].bounds;
UIView* overlay = [[UIView alloc] initWithFrame:mainWindowSize];
// Use colorWithRed:green:blue:alpha: or a solid color then manually tweak alpha
overlay.backgroundColor = [UIColor redColor];
overlay.alpha = 0.2; // transparency level
overlay.userInteractionEnabled = YES;
// Add it on top of the main window
UIWindow* mainWindow = (((MyAppDelegate*)
[UIApplication sharedApplication].delegate).window);
[mainWindow addSubview:overlay];
Caveats: You may have to manually hide the status bar. Also, this overlay view and its subviews are going to get all the user tap events. May want to make sure that's what you want.
push the view controller as a modalViewController....
if your view controller is AVC and assuming you use a navigation controller:
[self presentModalViewController:AVC animated:YES];
from the current view controller you're on.

iPhone UIViewController goes under status bar

I have a UIView and a UIController view. My is standard a 320x460 view. In applicationDidFinishLaunching I do:
[window addSubview:[controller view]];
The weird thing is that the UIView goes under the status bar (like there's missing outlet). However, if I rotate iPhone to the side and then back, it shows up ok.
Is this an expected behavior (I bet I can fix it by setting offset) or am I doing smth wrong?
I ran into this issue when displaying a UIViewController via presentModalViewController.
You can get around it by manually resizing the controller's view after the view has appeared:
- (void) viewDidAppear: (BOOL) animated {
//manually adjust the frame of the main view to prevent it from appearing under the status bar.
UIApplication *app = [UIApplication sharedApplication];
if(!app.statusBarHidden) {
[self.view setFrame:CGRectMake(0.0,app.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height - app.statusBarFrame.size.height)];
}
}
I think your problem is that when you add a view to a window, you need to be aware of the state of the status bar and compensate for it:
if showing the status bar :
[controller view].frame = CGRectMake(0, **20**, 320, 460);
else
[controller view].frame = CGRectMake(0, 0, 320, **480**);
this is why IB shows you a dummy status bar.
I add this issue today. It turned out that I had "Wants Full Screen" checked in the ViewController's Attribute inspector.
Turning off "Wants Full Screen" resolved the problem.
Finally, I got to this solution. Works well for both iPhone & iPad:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Allocate view controller and load nib file
if (isIPhone) {
self.mainViewController = [[[tfdMainViewController_iPhone alloc] initWithNibName:#"tfdMainViewController_iPhone" bundle:nil] autorelease];
} else {
self.mainViewController = [[[tfdMainViewController_iPad alloc] initWithNibName:#"tfdMainViewController_iPad" bundle:nil] autorelease];
}
// Offset correction (iPhone bug?)
CGRect r = self.mainViewController.view.frame;
r = CGRectOffset(r, 0, [UIApplication sharedApplication].statusBarFrame.size.height);
[self.mainViewController.view setFrame:r];
[window addSubview: self.mainViewController.view];
[self.window makeKeyAndVisible];
return YES;
}
P.S. For some reason view has correct height:
480 (screen height in iPhone Portrait mode) - 20 (status bar) = 460,
but failed to set vertical offset. It is pretty strange behavior, looks like bug.
Fixes to the window didn't work for me as I had a modal view. A UIModalPresentationCurrentContext modal view. OK, here's what worked for me. I've been searching the web up and down before getting this to work.
I'm unable to move the view.frame from the parent. However in the viewWillAppear I'm able to move it down:
- (void)viewWillAppear:(BOOL)animated
{
// Move down to compensate for statusbar
CGRect frame = parentView.navCon.view.frame;
frame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height;
parentView.navCon.view.frame = frame;
}
If you are using Interface Builder's "Simulated User Interface Elements", then you also need to make sure that you have set the flag for "Resize View From NIB" in your MainWindow nib.
This appears to be a bug in iOS 5. One fix would be to use wantsFullScreenLayout in whatever view controller needs to present modally and manually layout the view always below the status bar.
http://www.cocoanetics.com/2012/06/radar-view-frame-inconsistency-using-presentviewcontroller-wantsfullscreenlayout-yn/
http://openradar.appspot.com/radar?id=1758406
Are you manually setting the application bar hidden property AFTER adding the subview? I don't imagine this is the case, but if it's set to none when you first load the view it will layout as if there isn't one, and if you then set the status bar to not hidden it will pop up on top of your view.
A possible solution is to use [[controller view] setNeedsLayout]; after adding the subview, or possibly [window layoutSubviews];. I've never had a lot of success using those to fix layout problems, but since it works after a rotation it's worth a shot.
Even me too got the same issue. When we are using some coding for device orientation we have wrote some coding in app delegate or in our view controller. There we need to change the condition to use the orientation return YES or NO. That solved our issue.
I prefer to use UINavigationController to wrap the UIViewController you, after that, set the NavigationBarHidden to the UINavigationController. It's perfect solution cause UINavigationController do handle the height of status bar in iOS 7.
Here is my code and my screen capture.
UINavigationController *wrapNavController = [[UINavigationController alloc] initWithRootViewController:yourViewController] ;
[wrapNavController setNavigationBarHidden:YES] ;
The Xcode 6, iOS7/8 solution is in to uncheck the "Under Top Bars" checkmark in the "Extend Edges" section of the View Controller section of the Attributes Inspector.
For Xamarin.iOS it would be:
if (UIApplication.SharedApplication.StatusBarHidden == false)
{
var statusBarHeight = UIApplication.SharedApplication.StatusBarFrame.Height;
View.Frame = new CoreGraphics.CGRect(0, statusBarHeight, View.Frame.Width, View.Frame.Height - statusBarHeight);
}