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

时间:2014-03-13 21:21:48

标签: objective-c ios7 uinavigationcontroller uinavigationbar

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

这里有一些代码勾勒出我目前的做法:

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

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

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationFade;
}

要同时隐藏状态栏和导航栏,我会在同一个动画块中同时执行:

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 选项没有任何区别。)

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

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];

我最接近让它看起来正确的是按顺序显示条形而不是在同一个动画块中:

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];

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

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

另一个注意事项:万一它会有所不同,导航控制器会出现 theNavigationController.modalPresentationStyle = UIModalPresentationCustom

1 个答案:

答案 0 :(得分:1)

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

- (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];