62

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.

Cajunluke
  • 3,103
  • 28
  • 28
Biranchi
  • 16,120
  • 23
  • 124
  • 161
  • 4
    Just a comment, in case you are interested in publishing to Apple's app store -- the [Reeder app got rejected](http://twitter.com/#!/reederapp/status/125598161849942016) because of this feature. – phi Jan 20 '12 at 08:42
  • 1
    @Irene - I wrote a custom status bar view for my [Python for iOS](http://pythonforios.com) App and the update was recently approved for the App Store. Apple policy might have changed since the Reeder app was rejected though. – chown Oct 22 '12 at 19:09
  • A lot of apps in Appstore with this functionality – Sergey Kopanev Nov 20 '12 at 14:41

5 Answers5

87

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.

alleus
  • 6,077
  • 2
  • 23
  • 21
  • 1
    Note that placing an overlay over the regular status bar (the grey one) and the opaque black is simple. If your application has a translucent bar, you will need to hide it and place your own view in it's place (since placing a translucent bar on top of the original will only make a mess ;)) – alleus May 14 '10 at 12:48
  • Is that code missing a "return self;" at the end of the function there? – Ben Holland May 16 '12 at 17:14
  • For some reason, I am unable to get the view to show up when I set hidden to NO. Do I have to set the application window to this subclassed window? – chourobin Jun 14 '12 at 10:06
  • @chourobin No, simply initializing an UIWindow should be enough to add it to the screen. – alleus Jun 21 '12 at 13:22
  • Hey guys, can anyone please help me sort thing out with the approach @MartinAlléus suggested? My problem with it is here - http://stackoverflow.com/questions/14041446/click-through-uiwindows – Sergey Grischyov Dec 26 '12 at 14:32
  • 4
    For what it is worth, I was having a hard time getting the window to display, the reason was that I was not retaining the instance. It seems the application is very eager at releasing these under ARC environments so it will be released before it ever displays if you do not explicitly retain it as a instance variable/property. – Chris Wagner Mar 08 '13 at 09:04
  • @ChrisWagner Could you explain exactly what you have had to do, because I'm struggling with the same problem for hours but I can't make this working. thanks in advance – Heps Apr 10 '13 at 12:58
  • 1
    @MaciejHepner I had to retain the UIWindow, if no one was retaining it then it would get released and never show up. I actually ended up making the object create a retain cycle to retain itself, then in my dismissal I break the retain cycle so that it gets released. – Chris Wagner Apr 10 '13 at 16:45
  • This solution was fantastic until I saw what happens on iPad and orientation change - massive glitch :/ – Heps May 10 '13 at 10:40
  • This works for me but I would like to know how to have it on some ViewControllers but not all, like it seems to do when added. I'm able to hide it on ViewDidDisappear but this means when I switch between VCs that should have it, it flickers to hidden then not hidden again. – Chucky Jun 07 '17 at 14:51
  • @Chucky Not sure what would be the best solution, but one approach could be to have a queue system. Image having two methods, `-increaseShowCount` and `-decreaseShowCount` that simply does `+=1` and `-=1` to an `int` on the custom window class. When the counter goes higher than `0`, show the overlay, when it goes back to `0`, hide the overlay. Then you call `decrease` from `viewDidDisappear` and `increase` from `viewWillAppear`. That would stop your flickering. – alleus Jun 08 '17 at 15:10
58

I wrote a static library mimicing Reeders status bar overlay, you can find it here: https://github.com/myell0w/MTStatusBarOverlay

MTStatusBarOverlay 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!

myell0w
  • 2,200
  • 2
  • 21
  • 25
  • How do i use this if i dont have a status bar in my application. – Praveen S Jun 29 '11 at 10:45
  • 5
    Bad news guys, Apple started rejected apps using MTStatusBarOverlay or similar solutions that "displays a custom status bar overlay on top of the native status bar". Apparently it violates HIG :( – Błażej Apr 02 '12 at 11:37
  • 1
    It's true, unfortunately, some apps using MTStatusBarOverlay get rejected, but other don't. I regularly get messages from people using MTStatusBarOverlay in their apps without any (review-)probles, so it might still be worth a try for you :-) – myell0w May 14 '12 at 20:18
  • I think it's ok to MTStatusBarOverlay in the app. Tweetbot 3 is using this kind of UI extensively. (Showing you tweet sending progress.) – Hlung Dec 11 '13 at 11:22
4

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.

Sergey Kopanev
  • 1,496
  • 3
  • 17
  • 29
3

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.

A small icon on the top right of the screen alt text

Community
  • 1
  • 1
texmex5
  • 4,354
  • 1
  • 26
  • 28
1

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.

Lefteris
  • 14,550
  • 2
  • 56
  • 95