iOS 7中如何通过淡入/淡出来隐藏/显示状态栏和导航栏,就像照片应用程序一样?

3
我正在尝试通过淡入淡出来隐藏和显示状态栏和导航栏,就像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
你尝试过在动画块中将导航栏的alpha设置为0吗? - Noah Witherspoon
不,我会试一下。 - ememem
@NoahWitherspoon 在动画块中将导航栏的alpha设置为0,无论是淡入还是淡出,都会出现相同的问题。似乎导航栏想尽可能地贴近顶部,但使用[UIView transitionWithView...]时情况似乎有所不同。 - ememem
将导航栏的alpha属性设置为1而不是将hidden属性设置为NO,可以解决导航栏的毛玻璃/模糊背景未能淡入的问题。 - ememem
1个回答

1
我找到了自己问题的答案。诀窍是在淡入动画期间仅为导航栏设置框架、边界和中心而禁用动画。这可以通过子类化 UINavigationBar 并在设置框架、边界和中心时有条件地使用 [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];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接