如何通过淡入/淡出同时隐藏/显示状态栏和导航栏,如iOS 7中的照片应用程序?

问题描述:

我正试图隐藏并显示状态栏和导航栏,同时将它们放入和退出,就像iOS 7中的照片应用程序一样。我已经隐藏部分正常工作,但我遇到了问题与显示部分。问题是当我显示导航栏时,它最初定位好像状态栏不在那里。在淡入结束时,它被正确定位(向下移动以为状态栏腾出空间)。如何在整个动画过程中正确定位导航栏?

I'm trying to hide and show the status bar and the navigation bar by fading them in and out at the same time like the Photos app in iOS 7. I've got the hiding part working, but I am having trouble with the showing part. The problem is that when I show the navigation bar, it is initially positioned as if the status bar is not there. At the end of fading in, it is positioned correctly (it is shifted down to make room for the status bar). How can I get the navigation bar to be positioned correctly throughout the animation?

这里有一些代码勾勒出我当前的方法:

Here's some code sketching out my current approach:

在某些视图控制器中,我通过覆盖一些UIViewController方法来控制是否隐藏状态栏:

In some view controller, I control whether or not the status bar is hidden by overriding some UIViewController methods:

- (BOOL)prefersStatusBarHidden {
    return self.forcedStatusBarHidden;
}

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationFade;
}

要同时隐藏状态栏和导航栏,我同时执行这两项操作在同一动画块中:

To hide the status bar and navigation bar at the same time, I do both in the same animation block:

void (^animations)() = ^() {
    theNavigationController.navigationBar.hidden = YES;

    someViewController.forcedStatusBarHidden = YES;
    [someViewController setNeedsStatusBarAppearanceUpdate];
};
[UIView transitionWithView:theNavigationController.navigationBar.superview
                  duration:0.5
                   options:UIViewAnimationOptionCurveEaseInOut
                           | UIViewAnimationOptionTransitionCrossDissolve
                           | UIViewAnimationOptionAllowAnimatedContent
                animations:animations
                completion:nil];

(注意我使用 theNavigationController.navigationBar.hidden = YES 代替 [theNavigationController setNavigationBarHidden:YES animated:YES] 因为我希望导航栏淡出而不是向上滑动。另外,由于某种原因,不包括 UIViewAnimationOptionAllowAnimatedContent 选项不会使差异。)

(Notice I use theNavigationController.navigationBar.hidden = YES instead of [theNavigationController setNavigationBarHidden:YES animated:YES] because I want the navigation bar to fade instead of sliding up. Also, for some reason, not including the UIViewAnimationOptionAllowAnimatedContent option does not make a difference.)

但如果我做了类似的事情来同时显示状态栏和导航栏,我就会遇到我之前描述的问题。

But if I do something similar to show the status bar and navigation bar together, I get the problem I described earlier.

void (^animations)() = ^() {
    someViewController.forcedStatusBarHidden = NO;
    [someViewController setNeedsStatusBarAppearanceUpdate];

    theNavigationController.navigationBar.hidden = NO;
};
[UIView transitionWithView:theNavigationController.navigationBar.superview
                  duration:0.5
                   options:UIViewAnimationOptionCurveEaseInOut 
                           | UIViewAnimationOptionTransitionCrossDissolve
                           | UIViewAnimationOptionAllowAnimatedContent
                animations:animations
                completion:nil];

我最接近它的目的是按顺序显示条形而不是在同一个动画块中:

The closest I've gotten to getting it to look right is to show the bars in sequence instead of in the same animation block:

someViewController.forcedStatusBarHidden = NO;
[someViewController setNeedsStatusBarAppearanceUpdate];

void (^animations)() = ^() {
    theNavigationController.navigationBar.hidden = NO;
};
[UIView transitionWithView:theNavigationController.navigationBar.superview
                  duration:0.5
                   options:UIViewAnimationOptionCurveEaseInOut 
                           | UIViewAnimationOptionTransitionCrossDissolve
                           | UIViewAnimationOptionAllowAnimatedContent
                animations:animations
                completion:nil];

但现在酒吧不会一起消失。 (编辑:如果我将前两行放在他们自己的动画块中以强制状态栏的动画持续时间逐渐淡入,我会在导航栏中遇到原始问题。)如何修复此问题?

But now the bars do not fade in together. (EDIT: If I put the first two lines in their own animation block to force the animation duration of the status bar fading in, I get the original problem with the navigation bar.) How do I fix this?

注意:我正在使用导航栏的自定义背景图像。如果我只使用导航栏的默认磨砂/模糊背景,另一个问题是,当背景淡入并且突然出现在淡入动画结束时,背景是不可见的。如果我能够在磨砂/模糊背景下工作,那就太棒了。

Note: I'm using a custom background image for the navigation bar. If I just use the default frosted/blurred background for the navigation bar, another problem is that the background is invisible when it is supposed to be fading in and suddenly appears at the end of the fade-in animation. If I can get this working for the frosted/blurred background as well, that would be great.

另外注意:为了防止它有所不同,导航控制器是提出 theNavigationController.modalPresentationStyle = UIModalPresentationCustom

Another note: Just in case it makes a difference, the navigation controller is presented with theNavigationController.modalPresentationStyle = UIModalPresentationCustom.

我找到了自己问题的答案。诀窍是禁用动画,仅用于在淡入动画期间设置导航栏的框架,边界和中心。这是通过继承 UINavigationBar 并在设置了frame,bounds和center时有条件地使用 [UIView performWithoutAnimation ...] 来完成的。例如:

I figured out the answer to my own question. The trick is to disable the animation just for setting the frame, bounds, and center for the navigation bar during the fade-in animation. This is done by subclassing UINavigationBar and conditionally using [UIView performWithoutAnimation...] whenever the frame, bounds, and center are set. For example:

- (void)setFrame:(CGRect)frame
{
    if (self.shouldAnimateDimensions) {
        [super setFrame:frame];
    }
    else {
        [UIView performWithoutAnimation:^{
            [super setFrame:frame];
        }];
    }
}

然后,淡入代码变为:

void (^animations)() = ^() {
    // myNavigationBar is theNavigationController.navigationBar
    myNavigationBar.shouldAnimateDimensions = NO;

    someViewController.forcedStatusBarHidden = NO;
    [someViewController setNeedsStatusBarAppearanceUpdate];

    myNavigationBar.shouldAnimateDimensions = YES;

    theNavigationController.navigationBar.hidden = NO;
};
[UIView transitionWithView:theNavigationController.navigationBar.superview
                  duration:0.5
                   options:UIViewAnimationOptionCurveEaseInOut 
                           | UIViewAnimationOptionTransitionCrossDissolve
                           | UIViewAnimationOptionAllowAnimatedContent
                animations:animations
                completion:nil];