UIStatusBar as in Facebook new iOS7 application

2019-02-02 18:30发布

问题:

I have an app with side bar menu, kinda like Facebook side bar menu. I'm using this class called SWRevealViewController and it's working great. Now since iOS7 has came out, I just can't figure out how to adjust my Status and Navigation Bar to be like in Facebook app.

As you can see, in the Facebook app, when the user slides the screen and open's the menu, the status bar turn from the Navigation Bar blue color to black with Fade animation. In my app, the user slides the screen to open the menu and the status bar with the blue color (that is blue because of that view NavigationBar) won't fade away and change the color into black.

Also, another issue that I'm having, I just can't change the StatusBar text color to white. I've tried everything, every piece of code on the internet, read all apple's documentation, but still couldn't manage to change the color.

I also used this code:

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationFade;
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

- (BOOL)prefersStatusBarHidden
{
    return NO;
}

Thanks in advance.

========================================================================

UPDATE: The solution to this problem as in @yoeriboven answer is to put 2 views on top of the SWRevealViewController with black color and blue color and just animate the two, this is a great solution and it worked just great.

So, when creating the revealController I've created 2 blank UIViews and added them, one blue and one black. One of them, the black one, I kept hidden for now.

self.revealController = [[SWRevealViewController alloc] initWithRearViewController:nil frontViewController:self.frontViewController];
self.revealController.delegate = self;

self.appDelegate.window.rootViewController = self.revealController;

self.statusBarBlack = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.appDelegate.window.frame.size.width, 20)];
[self.statusBarBlack setBackgroundColor:[UIColor blackColor]];

self.statusBarBlue = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.appDelegate.window.frame.size.width, 20)];
[self.statusBarBlue setBackgroundColor:[UIColor blueColor]];

[self.appDelegate.window.rootViewController.view addSubview:self.statusBarBlack];
[self.appDelegate.window.rootViewController.view addSubview:self.statusBarBlue];

Now if you are using SWRevealViewController you can use the next code, if not, just build it on your own, inside SWRevealViewController.m just #import "AppDelegate.h" and than replace the touchesMoved method with this one:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];

    if (self.state == UIGestureRecognizerStateFailed)
        return;

    //  Change color of status bar by the location of your swipe
    AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    UITouch *currentTouch = [touches anyObject];
    CGPoint currentTouchLocationOnWindow = [currentTouch locationInView:appDelegate.window];
    appDelegate.splashScreen.blueStatusBar.alpha = currentTouchLocationOnWindow.x / appDelegate.window.frame.size.width;

    if ( _dragging )
        return;

    const int kDirectionPanThreshold = 5;

    UITouch *touch = [touches anyObject];
    CGPoint nowPoint = [touch locationInView:self.view];

    CGFloat moveX = nowPoint.x - _init.x;
    CGFloat moveY = nowPoint.y - _init.y;

    if (abs(moveX) > kDirectionPanThreshold)
    {
        if (_direction == SWDirectionPanGestureRecognizerHorizontal)
            _dragging = YES;
        else
            self.state = UIGestureRecognizerStateFailed;
    }
    else if (abs(moveY) > kDirectionPanThreshold)
    {
        if (_direction == SWDirectionPanGestureRecognizerVertical)
            _dragging = YES ;
        else
            self.state = UIGestureRecognizerStateFailed;
    }
}

Now go down a little bit and search for the method rightRevealToggleAnimated and replace her with this one:

- (void)rightRevealToggleAnimated:(BOOL)animated
{
    FrontViewPosition toogledFrontViewPosition = FrontViewPositionLeft;
    if (_frontViewPosition >= FrontViewPositionLeft) {
        toogledFrontViewPosition = FrontViewPositionLeftSide;
        [UIView animateWithDuration:0.3 animations:^{
            //  Change color of status bar
            AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
            appDelegate.splashScreen.blueStatusBar.alpha = 0.0;
        }];
    } else {
        [UIView animateWithDuration:0.3 animations:^{
            //  Change color of status bar
            AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
            appDelegate.splashScreen.blueStatusBar.alpha = 1.0;
        }];
    }

    [self setFrontViewPosition:toogledFrontViewPosition animated:animated];
}

That should do the trick, enjoy!

回答1:

In iOS 7, your view controllers' view is full screen. So you could just put two views on top of each other at the top 22 px (status bar height) of the view. The bottom one black and the top one the same color as your navigation bar. When swiping to the SWRevealViewController, with one of the UIScrollView delegate methods you can calculate how far it is in percentages and apply that value to the opacity of the subview with your navigation bar's color.



回答2:

I had another approach that worked like a charm too.

first int the SWRevealViewController.h at the SWRevealView class I create a View @property called underStatusBarView to be put at the status bar position.

then in the - (id)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller method I instantiate the @property set its color to black and its alpha to 0.

- (id)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller
{
    self = [super initWithFrame:frame];
    if ( self )
    {
        _c = controller;
        CGRect bounds = self.bounds;

        _frontView = [[UIView alloc] initWithFrame:bounds];
        _frontView.autoresizingMask =   UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

        [self addSubview:_frontView];

        CALayer *frontViewLayer = _frontView.layer;
        frontViewLayer.masksToBounds = NO;
        frontViewLayer.shadowColor = [UIColor blackColor].CGColor;

        /* Here starts my under status bar implementation */
        CGRect statusFrame = [[UIApplication sharedApplication]statusBarFrame];
        _underStatusBarView = [[UIView alloc]initWithFrame:statusFrame];
        [_underStatusBarView setBackgroundColor:[UIColor blackColor]];
        [_underStatusBarView setAlpha:0.0];
        [self addSubview:_underStatusBarView];
        /* here it ends */

        //frontViewLayer.shadowOpacity = 1.0f;
        frontViewLayer.shadowOpacity = _c.frontViewShadowOpacity;
        frontViewLayer.shadowOffset = _c.frontViewShadowOffset;
        frontViewLayer.shadowRadius = _c.frontViewShadowRadius;
    }

    return self;
}

Then I added a single line of code to the private method responsible for laying out the rear views - (void)_layoutRearViewsForLocation:(CGFloat)xLocation to change the _underStatusBarView alpha according to the front view location.

- (void)_layoutRearViewsForLocation:(CGFloat)xLocation
{
    CGRect bounds = self.bounds;

    CGFloat rearRevealWidth = _c.rearViewRevealWidth;
    if ( rearRevealWidth < 0) rearRevealWidth = bounds.size.width + _c.rearViewRevealWidth;

    CGFloat rearXLocation = scaledValue(xLocation, -_c.rearViewRevealDisplacement, 0, 0, rearRevealWidth);

    CGFloat rearWidth = rearRevealWidth + _c.rearViewRevealOverdraw;
    _rearView.frame = CGRectMake(rearXLocation, 0.0, rearWidth, bounds.size.height);

    CGFloat rightRevealWidth = _c.rightViewRevealWidth;
    if ( rightRevealWidth < 0) rightRevealWidth = bounds.size.width + _c.rightViewRevealWidth;

    CGFloat rightXLocation = scaledValue(xLocation, 0, _c.rightViewRevealDisplacement, -rightRevealWidth, 0);

    CGFloat rightWidth = rightRevealWidth + _c.rightViewRevealOverdraw;
    _rightView.frame = CGRectMake(bounds.size.width-rightWidth+rightXLocation, 0.0f, rightWidth, bounds.size.height);

    /*this line changes the under status bar view alpha*/
   _underStatusBarView.alpha = xLocation/rearRevealWidth;
}

How you are using the rightRevealView you should change the rearRevealWidht to rightRevealWidth just to prevent future compatibility issues.



回答3:

I really liked your approach. I've made a couple updates to your code and want to submit it to the project. If you have any issues with me doing so, please let me know.