Slide UIPageViewController page over the status bar

820 Views Asked by At

I am trying to find a clean way to handle UIPageViewController and the status bar. I noticed Snapchat does it perfectly by sliding the viewcontroller OVER the status bar when you are sliding to a new page that does not show the status bar. It looks like this...

snapchat statusbar uipageviewcontroller

Does anyone know how this is being done? The only way I can think of is by using a different UIWindow, but how would you implement a UIPageViewController with multiple UIWindows? If that is even what is being done. Otherwise how is this effect being achieved?

2

There are 2 best solutions below

0
On

Ok so this is actually done using some clever tricks.

Basically it's not actually moving the status bar, its moving an image of the status bar.

Disclaimer: I YOLO'd this implementation so I make no guarantees on if it'll work out of the box

Starting with iOS7 you can take a picture using

UIView *screen = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];

There's a bit more useful information I saw here. But basically the status bar is cropped from the picture and added to a UIWindow with a windowLevel above UIWindowStatusLevelBar that will mask the real status bar. Something like:

UIWindow *statusBarWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
statusBarWindow.windowLevel = UIWindowLevelStatusBar;
statusBarWindow.hidden = NO; // fun fact you don't have to add a UIWindow to anything, just setting hidden = NO should display it
statusBarWindow.backgroundColor = [UIColor clearColor]; // I have no idea if this is necessary but since it's now visible you def don't want it to have a color

...

// The view that will hold the screen shot
UIView *statusBarView = [[UIView alloc] initWithFrame:[UIApplication sharedApplication].statusBarFrame];
statusBarView.clipsToBounds = YES;

// Now we add the screen shot we took to this status bar view
[statusBarView addSubview:screen]; // screen is the UIView from previous code block

// Now add this statusBarView with the image to the window we created
[statusBarWindow addSubview:statusBarView];

Now the rest really depends on what your implementation is looking like but from here you really just need to handle moving the view with either a pan, or whatever action is causing the new view to come in through the side:

// you're going to want to hide the status bar when this action starts so that your new window is visible
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];

// then inside whatever method is handling the sliding you're going to adjust the frame of the statusBarView
// this can be done explicitly by setting a new frame, or animating its x position, or whatever

// if you're doing it explicitly something like:
CGFloat offset = self.viewThatIsScrolling.contentOffset.x; // may be negative depending on direction that is being swiped
statusBarView.frame = CGRectMake(offset, 0, self.statusBarView.frame.width, 20.0f);
// or maybe even
statusBarView.transform = CGAffineTransformMakeTranslation(offset -previousOffsetAmount, 0); // you only want it to move over by whatever new amount so it can match up, this will have to be tracked somehow if you go this route

... 

// and finally once the 'sliding' is done don't forget to remove the screenshot and unhide the status bar
// (can check by looking at the offset value from earlier or as a callback after animation, or whatever)
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
[statusBarView removeFromSuperview];
statusBarView = nil;

Also note this doesn't handle orientation changes or anything (the fixed frame might cause it to not work). you could probably use autoResizingMask or something

0
On

Basically create a UIViewController, put the UIPageViewController inside that. Make the size of UIVC the size of iphone screen. Then set the appdelegate.window.rootviewcontroller as your UIViewControllers

Here is a great example repo for this task: https://github.com/goktugyil/EZSwipeController