同时如何滑动状态栏和导航栏?

4
我希望通过滑动效果同时显示和隐藏状态栏和导航栏,以下是我的尝试:
[[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
[self.navigationController setNavigationBarHidden:hide animated:animated];

然而,这两个动画的持续时间并不相同。状态栏动画需要更长的时间。 我找不到指定任何一个动画持续时间的方法。 我错过了什么明显的东西吗?


我向苹果提交了一个错误报告:http://openradar.appspot.com/8548087 如果你也受到影响,请重复报告。 - Ortwin Gentz
7个回答

5

ios-lizard的回答几乎满足了我的要求,但是在旋转设备时,导航栏会重新出现,除非正确设置hidden。因此,对我而言,以下内容有效:

隐藏动画很好看!太棒了!!

显示动画还不错(我希望能让状态栏与导航栏一起滑动,但至少我们不再看到间隙了。:D

- (void)toggleFullscreen {

    UINavigationBar *navBar = self.navigationController.navigationBar;
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
    float animationDuration;
    if(statusBarFrame.size.height > 20) { // in-call
        animationDuration = 0.5;
    } else { // normal status bar 
        animationDuration = 0.6;
    }

    _fullscreen = !_fullscreen;
    if (_fullscreen) { 
        // Change to fullscreen mode
        // Hide status bar and navigation bar
        [[UIApplication sharedApplication] setStatusBarHidden:YES
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:animationDuration animations:^{
            navBar.frame = CGRectMake(navBar.frame.origin.x,
                                  -navBar.frame.size.height,
                                  navBar.frame.size.width,
                                  navBar.frame.size.height);
        } completion:^(BOOL finished) {
            [self.navigationController setNavigationBarHidden:YES animated:NO];
        }];

    } else {
        // Change to regular mode
        // Show status bar and navigation bar
        [[UIApplication sharedApplication] setStatusBarHidden:NO
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:animationDuration animations:^{
             navBar.frame = CGRectMake(navBar.frame.origin.x,
                                       statusBarFrame.size.height,
                                       navBar.frame.size.width,
                                       navBar.frame.size.height);
        } completion:^(BOOL finished) {
            [self.navigationController setNavigationBarHidden:NO animated:NO];
        }];

    }

}

2
这是我为我的应用程序解决此问题的方法。
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];

    // delta is the amount by which the nav bar will be moved
    delta = statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height;

    if(statusBarFrame.size.height>20) { // in-call
        animationDuration = 0.5;
    }
    else { // normal status bar 
        animationDuration = 0.6;
    }

    // hide status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];

    // hide nav bar
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];

    self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -delta);

    [UIView commitAnimations];

1

nacho4d的回答几乎符合我的要求。但是,他在navBar可见之前更改了navBar的frame。因此,我们看不到过渡动画。它看起来像navBar突然出现。更重要的是,在显示时,statusBarFrame.size.height等于0。这是他的代码:

[[UIApplication sharedApplication] setStatusBarHidden:NO
                                            withAnimation:UIStatusBarAnimationSlide];
    [UIView animateWithDuration:animationDuration animations:^{
         navBar.frame = CGRectMake(navBar.frame.origin.x,
                                   statusBarFrame.size.height,
                                   navBar.frame.size.width,
                                   navBar.frame.size.height);
    } completion:^(BOOL finished) {
        [self.navigationController setNavigationBarHidden:NO animated:NO];
    }];

当显示时,我们希望能够使状态栏与导航栏一起滑动。以下是我的答案:
        UINavigationBar *navBar = self.navigationController.navigationBar;
        [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationSlide];

        [UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            // make navigationBar visual
            if (!hidden)
            {
                [self.navigationController setNavigationBarHidden:hidden animated:NO];
            }

            navBar.frame = CGRectMake(navBar.frame.origin.x,
                                      hidden ? -navBar.frame.size.height : 20,
                                      navBar.frame.size.width,
                                      navBar.frame.size.height);
        } completion:^(BOOL finished) {
            if (hidden)
            {
                [self.navigationController setNavigationBarHidden:hidden animated:NO];
            }
        }];
  1. 当隐藏时,且 hidden 等于 NO。我们应该先改变 navBar 的 frame,然后再将 navBar 隐藏。
  2. 当显示时,且 hidden 等于 YES。我们先使 navBar 可见,然后再改变其 frame。
  3. 我们选择 UIViewAnimationOptionCurveEaseOut,以使其看起来更好。

1
这里有一个更为简明的方法,使用系统常量来控制动画持续时间,并且还可以处理来电。
请注意,navigationBar是一个出口,statusBarHeight是一个实例变量浮点数。
- (IBAction)toggleControls:(id)sender {
    BOOL isHidden = ! [UIApplication sharedApplication].statusBarHidden;
    if (isHidden)
        statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
    [UIView animateWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration animations:^{
        self.navigationBar.frame = CGRectMake(self.navigationBar.frame.origin.x,
                                              isHidden ? -self.navigationBar.frame.size.height : statusBarHeight,
                                              self.navigationBar.frame.size.width,
                                              self.navigationBar.frame.size.height);
    }];
    [[UIApplication sharedApplication] setStatusBarHidden:isHidden withAnimation:UIStatusBarAnimationSlide];
}

1

显然,没有简单的解决方案来正确地完成这个任务。苹果必须修复它

当然,一个解决方法是使用 Ephraim 建议的 alpha fading。如果你坚持要滑动行为,我发现最好只是动画化导航栏并隐藏/显示状态栏而不进行任何动画。这比滑动状态栏看起来更好,因为在动画期间两个栏之间的间隙非常明显。


0

这不算是一个很好的答案,但它能够工作。所以我做的是:

// This method gets called by whatever action you want

- (void) toggleShowStatusNavBars:(id)sender {

    // Assuming you have a ivar called barsHidden

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.4]; // This is IMPORTANT, 0.4s

    self.navigationController.navigationBar.alpha = (barsHidden?1.0:0.0);  

    barsHidden = !barsHidden; 

    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(setStatusBarHidden)];

    [UIView commitAnimations];
}

- (void) setStatusBarHidden {
    [[UIApplication sharedApplication] setStatusBarHidden:barsHidden animated:YES];
}

这将基本上同步动画的开始(因为您在导航栏动画开始时调用了setStatusBarHidden)。关键部分是状态栏动画似乎需要0.4秒。

这对我有用,但如果您找到更好的方法,请在此处发布。


你正在使用alpha淡出来隐藏navBar。这种方法更容易,因为在这种情况下,你可以直接操作navBar。但在我感兴趣的滑动情况下,这不是可行的方法,因为navigationController也会操作内容视图框架。 - Ortwin Gentz

0
你可以使用实例变量来实现这个功能:
self.navigationController setNavigationBarHidden:hide animated:animated];
_shouldHideStatusBar = hide;

并实现以下函数:

- (BOOL)prefersStatusBarHidden{
    return _shouldHideStatusBar;
}

setNavigationBarHidden:animated函数将自动调用prefersStatusBarHidden函数。如果没有,则可以使用以下UIViewController方法调用该函数:

[self setNeedsStatusBarAppearanceUpdate];

当然,您可以使用以下代码选择状态栏隐藏动画样式:

- (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationSlide;
}

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