Gyfis
Gyfis

Reputation: 1174

Moving status bar in iOS 7

The problem I'm facing is this:

I want to implement an iOS 7 app with nice design and left/right menu, which appears after the main view animate itself to the right/left. I'm doing this with [UIView animateWithDuration...] code, but that's not really important. What I want to achieve is the same effect the Mailbox iOS 7 app has: to move the status bar away (to the right/left) with the main view

Image for better explanation:

Mailbox app with status bar moved to the side

What I only found is this article about the issue, with some working code using Private APIs, which I'd like not to use, since I want my app to be accepted on the App Store.

I'd like to achieve the same effect ('legally'). Does anybody knows how to?

Thanks!

Upvotes: 36

Views: 14738

Answers (5)

Simon Holroyd
Simon Holroyd

Reputation: 934

The gist of it is to use this method introduced in iOS 7:

https://developer.apple.com/documentation/uikit/uiscreen/1617814-snapshotview:

With that you get a UIView containing a screenshot that includes the status bar. Once you have that, it's just a matter of hiding your current view then pushing the screenshot view around.

I posted a proof of concept here: https://github.com/simonholroyd/StatusBarTest

NOTE I haven't submitted code that does this through the Apple review process, but this is not a private API method.

Upvotes: 48

signal
signal

Reputation: 225

I use this method to move statuebar with slider view,in a application there are two window,one normal window,other statuBarWindow,i get statuBarView which superView is statuBarWindows ,and move it with slider view.

- (UIView *)statuBarView
{
    NSString *key = [[NSString alloc] initWithData:[NSData dataWithBytes:(unsigned char []){0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x61, 0x72} length:9] encoding:NSASCIIStringEncoding];
    id object = [UIApplication sharedApplication];
    UIView *statusBar = nil;
    if ([object respondsToSelector:NSSelectorFromString(key)]) {
        statusBar = [object valueForKey:key];
    }
    return statusBar;
}

Upvotes: 7

Gyfis
Gyfis

Reputation: 1174

So, after the initial push by Mr. Simon Holroyd and some searching, I've found the solution of how to achieve this "effect" functionality. This is the code:

statusbarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];

EDIT: mister pcholberg correctly pointed out that the former code did not work on the actual device, only on the iOS Simulator, so I've edited it by his recommendation

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    UIView *screenShot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
    [statusbarView addSubview:screenShot];
    [statusbarView setClipsToBounds:YES];
    [self.view addSubview:statusbarView];

    [self setPrefersStatusBarHidden:YES];
    [self prefersStatusBarHidden];
    [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
}

...

- (BOOL)prefersStatusBarHidden
{
    return prefersStatusBarHidden;
}

...


So the first part creates context, uses the method Simon mentioned, draws the view with the statusbar, and saves that as an UIImage

The second part adds the snapshot UIView to my viewController's UIView

And the third part sets my bool for statusbar to YES (for easier use in the method above), and calls methods to redraw it

This then sets the UIView as not-functional statusbar at its place and hides the original one, so there is no double-rendering. Then I can use this view in my [UIView animateWithDuration... method

And when I return, I use this code in the completion handler of the animation block:

[statusbarView removeFromSuperview];

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{

    [self setPrefersStatusBarHidden:NO];
    [self prefersStatusBarHidden];
    [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];

}

And voilá! This works as the described effect in my question.

Hope this helps somebody!

Upvotes: 7

simonbs
simonbs

Reputation: 8042

I just created BSPanViewController which makes it extremely easy to achieve this effect. The control and instructions on how to use it can be found on GitHub.

The implementation is the same as the one explained by Simon Holroyd.

Upvotes: 3

note173
note173

Reputation: 1875

In my experience, App Store reviewers generally don't care about private API's use, especially this simple and harmless. For the task you can get a pointer to application's status bar view through several methods, which you can find in iOS complete headers like https://github.com/nst/iOS-Runtime-Headers

Upvotes: -3

Related Questions