14

我想在点击时切换状态栏的可见性,就像在照片应用中一样。

在 iOS 7 之前,这段代码运行良好:

-(void)setStatusBarIsHidden:(BOOL)statusBarIsHidden {

    _statusBarIsHidden = statusBarIsHidden;

    if (statusBarIsHidden == YES) {

        [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];


    }else{

        [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];

    }

}

但我无法让它在 iOS 7 中工作。我找到的所有答案都只提供永久隐藏栏而不是切换的建议。

然而,既然照片做到了,就一定有办法。

4

8 回答 8

44

默认情况下,在 iOS 7 或更高版本上,要隐藏特定视图控制器的状态栏,请执行以下操作:

  1. 如果您要隐藏状态栏的视图控制器正在以模态方式呈现而modalPresentationStyle不是,请在呈现控制器之前UIModalPresentationFullScreen手动设置modalPresentationCapturesStatusBarAppearance为(例如,在或者如果您正在使用情节提要)YES-presentViewController:animated:completion-prepareForSegue:
  2. 在提供的控制器中覆盖-prefersStatusBarHidden并返回适当的值
  3. 调用setNeedsStatusBarAppearanceUpdate呈现的控制器

如果要为其外观或消失设置动画,请在动画块中执行第三步:

[UIView animateWithDuration:0.33 animations:^{
    [self setNeedsStatusBarAppearanceUpdate];
}];

您还可以通过从呈现的控制器中返回适当的UIStatusBarAnimation值来设置动画的样式。-preferredStatusBarUpdateAnimation

于 2013-10-05T06:49:48.767 回答
7

首先View controller-based status bar appearance在 Info.plist 中设置为YES

这个 Swift 示例展示了如何在按下按钮后使用动画切换状态栏。

import UIKit

class ToggleStatusBarViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func prefersStatusBarHidden() -> Bool {
        return !UIApplication.sharedApplication().statusBarHidden
    }

    override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
        return UIStatusBarAnimation.Slide
    }

    @IBAction func toggleStatusBar(sender: UIButton) {
        UIView.animateWithDuration(0.5,
            animations: {
                self.setNeedsStatusBarAppearanceUpdate()
        })
    }
}
于 2015-07-22T08:31:26.667 回答
5

我能够简化@Jon 的回答,并且仍然得到与 iOS 7 上的照片应用程序无法区分的行为。看起来不需要显示时的延迟更新。

- (IBAction)toggleUI:(id)sender {
    self.hidesUI = !self.hidesUI;

    CGRect barFrame = self.navigationController.navigationBar.frame;

    CGFloat alpha = (self.hidesUI) ? 0.0 : 1.0;
    [UIView animateWithDuration:0.33 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
        self.navigationController.navigationBar.alpha = alpha;
    }];

    self.navigationController.navigationBar.frame = CGRectZero;
    self.navigationController.navigationBar.frame = barFrame;
}

- (BOOL)prefersStatusBarHidden {
    return self.hidesUI;
}
于 2014-01-13T22:43:27.277 回答
4

这可能被认为是一种 hack,但它是我最接近重现效果的方法。还有一个小问题。淡出时,您可以看到导航栏从顶部调整大小。它足够微妙,但仍然不是完美的褪色。如果有人知道如何修复它,请告诉我!

- (BOOL)prefersStatusBarHidden {

    if (_controlsAreHidden == YES)
        return YES;
    else
        return NO;
}

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {

    return UIStatusBarAnimationFade;
}

-(void)setControlsAreHidden:(BOOL)controlsAreHidden {

    _controlsAreHidden = controlsAreHidden;

    if (controlsAreHidden == YES) {

        // fade out
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        [UIView animateWithDuration:0.3 animations:^ {


            [self setNeedsStatusBarAppearanceUpdate];

            self.navigationController.navigationBar.alpha = 0;



        }];


        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 44);



    }else{


        // fade in
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 64);

        [UIView animateWithDuration:0.3 animations:^ {

            [self setNeedsStatusBarAppearanceUpdate];

            self.navigationController.navigationBar.alpha = 1;

        }];


    }

}
于 2013-10-02T03:34:58.563 回答
3

这段代码工作得很好:

-(void)setControlsAreHidden:(BOOL)controlsAreHidden {

    if (_controlsAreHidden == controlsAreHidden)
        return;

    _controlsAreHidden = controlsAreHidden;


    UINavigationBar * navigationBar = self.navigationController.navigationBar;

    if (controlsAreHidden == YES) {

        // fade out
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        [UIView animateWithDuration:0.3 animations:^ {
            [self setNeedsStatusBarAppearanceUpdate];
            self.navigationController.navigationBar.alpha = 0;
        }];

        self.navigationController.navigationBar.frame = CGRectZero;
        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 44);

    } else {

        // fade in
        //
        [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^ {
            [self setNeedsStatusBarAppearanceUpdate];
        }];

        double delayInSeconds = 0.01;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

            [self.navigationController setNavigationBarHidden:NO animated:NO];
            navigationBar.alpha = 0;
            [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^ {
                navigationBar.alpha = 1;
            }];

        });

    }

}
于 2013-11-16T01:39:53.523 回答
3

实际上现在需要弄乱导航栏框架。您只需使用 2 个单独的动画块即可实现流畅的动画效果。像这样的东西应该可以正常工作。

@property (nonatomic, assign) BOOL controlsShouldBeHidden;

...

- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated {

    if (self.controlsShouldBeHidden == hidden) {
        return;
    }

    self.controlsShouldBeHidden = hidden;

    NSTimeInterval duration = animated ? 0.3 : 0.0;

    [UIView animateWithDuration:duration animations:^(void) {

        [self setNeedsStatusBarAppearanceUpdate];

    }];

    [UIView animateWithDuration:duration animations:^(void) {

        CGFloat alpha = hidden ? 0 : 1;
        [self.navigationController.navigationBar setAlpha:alpha];

    }];

}

- (BOOL)prefersStatusBarHidden {

    return self.controlsShouldBeHidden;

}

为了与 iOS 6 兼容,请务必检查[self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]

于 2014-01-23T09:57:42.600 回答
1

要更正导航栏在淡出时向上滑动的问题,您应该添加以下代码:

self.navigationController.navigationBar.frame = CGRectZero;

进入以下代码行之前的“淡入”部分:

self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 64);

这是必要的,因为框架是相同的,设置相同的框架将被忽略,并且不会阻止导航栏滑动。因此,您需要将框架更改为不同的内容,然后再次将其设置为正确的框架以触发更改。

于 2013-10-15T03:02:04.497 回答
1

解决此问题的方法取决于应用 plist 中“基于控制器的状态栏外观”设置的值。

如果“查看基于控制器的状态栏外观”NO在您的 plist 中,则此代码应该可以工作:

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];

如果“基于视图控制器的状态栏外观”打开,在您的视图控制器中,添加此方法:

- (BOOL) prefersStatusBarHidden {
    // I've hardcoded to YES here, but you can return a dynamic value to meet your needs for toggling
    return YES;
}

对于切换,当您想根据上述方法的值更改状态栏是否隐藏/显示时,您的视图控制器可以调用该setNeedsStatusBarAppearanceUpdate方法。

于 2013-10-01T19:57:52.320 回答