【问题标题】:How to fade out the status bar while not hiding it如何淡出状态栏而不隐藏它
【发布时间】:2014-01-23 08:57:35
【问题描述】:

iOS 开发者肯定知道关于状态栏和著名的“幻灯片/汉堡包/抽屉”的问题。这个问题在这里得到了很好的解释:http://uxmag.com/articles/adapting-ui-to-ios-7-the-side-menu

我正在使用MMDrawerController 库,它有一个很好的技巧,可以让我们在容器视图控制器上方创建一个虚拟状态栏。不幸的是,这并不是很好。有什么新的消息?消息是,我偶然发现了一个应用程序 (Tinder),它完美地解决了这个令人兴奋的问题。我创建了一个 gif,完美地展示了 Tinder 的功能。

需要等待几秒钟才能看到 gif,因为其中有一个错误,我不知道如何解决。只需等待一/两秒,您就可以正确看到 gif。


无论如何,Tinder 是做什么的?当用户点击左上角的菜单按钮并开始向右滑动时,状态栏淡出。当视图恢复到原始位置时,状态栏将再次显示。

对此我既高兴又有点难过,因为这意味着必须这样做,但我真的不知道如何实现它(也许是 hacking MMDrawerController)。任何帮助将不胜感激。


重要

请注意setStatusBarHidden:方法将完全隐藏状态栏,这意味着整个视图的高度为-20px。这显然不是解决方案,因为正如您从 gif 中看到的那样,视图没有被拉伸。

【问题讨论】:

  • 你在使用自动布局吗?
  • 难道该应用程序被设计为无论是否隐藏状态栏都一样吗?例如,通过对 contentView 顶部使用约束而不是使用顶部布局指南?这将解决 -20px 问题,但显然需要调整应用程序。
  • Taum 问题是,如果我使用 setStatusBarHidden: 方法,动画将隐藏状态栏,因此在视图控制器适应新高度时会有一个丑陋的动画。
  • @FredCollins 发生了什么我的回答不起作用。

标签: iphone objective-c cocoa-touch animation ios7


【解决方案1】:

您的主要问题是MMDrawerController。如果你深入研究它,你会发现很多与状态栏相关的方法,例如setShowsStatusBarBackgroundViewsetStatusBarViewBackgroundColor 等等。当状态栏被隐藏时,他们的代码中的某些内容会向上推视图。

您也可以使用另一个抽屉控制器或使用自定义代码。

这里有一个简单的方法来完成这个:

ViewControllerA:

-(BOOL)prefersStatusBarHidden
{
    return _hidden;
}
- (void)statusHide
{
    [UIView animateWithDuration:0.4 animations:^() {[self setNeedsStatusBarAppearanceUpdate];
    }completion:^(BOOL finished){}];
}

ViewControllerB:(ViewControllerA 中的容器)

- (IBAction)move:(UIButton *)sender
{
    parent = (ViewController*)self.parentViewController;
    parent.hidden = !parent.hidden;
    CGRect frame = parent.blueContainer.frame;
    if(parent.hidden)
    {
        frame.origin.x = 150;
    }
    else
    {
        frame.origin.x = 0;
    }

    [UIView animateWithDuration:1 animations:^() {parent.blueContainer.frame = frame;}completion:^(BOOL finished){}];
    [parent statusHide];
}

对于 iOS 6 兼容使用:

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

表格视图和其他子视图将留在它们的位置,不会被向上推。

编辑:

添加导航栏:

UINavigationController 会将其 UINavigationBar 的高度更改为 要么 44 分,要么 64 分,取决于一个相当奇怪和 未记录的一组约束。如果 UINavigationController 检测到 其视图框架的顶部在视觉上与其 UIWindow 的顶部,然后它绘制它的导航栏,高度为 64 点。如果其视图的顶部与 UIWindow 的顶部不连续 (即使只偏离一点),然后它会在其中绘制导航栏 高度为 44 点的“传统”方式。这个逻辑是 由 UINavigationController 执行,即使它是几个孩子 在应用程序的视图控制器层次结构中。那里 没有办法阻止这种行为。

取自here

您可以非常简单地继承 UINavigationController 并创建自己的导航栏来避免这种烦恼。

【讨论】:

  • 哦,非常好啊!你介意分享你的简单测试项目吗? :) 无论如何,我不认为问题出在“MMDrawerViewController”。我应该查看它的代码并尝试解决这个问题!
  • 我刚刚尝试过您展示的相同操作,并且仅当中心视图控制器不是导航控制器时才有效。我认为这是因为导航控制器有一个导航栏附加到顶部布局指南并尝试修复它。您的中心/右视图控制器是导航控制器吗?浅蓝色视图是导航栏?
  • 是的,如果我尝试添加一个简单的UINavigationBar,它可以工作,但如果控制器是具有自己导航栏的导航控制器则无法工作,因为该栏试图保持连接到顶部。嗯
  • @FredCollins 以上完全回答了这个问题。我不认为 Tinder 使用的是通用导航栏。感染,我几乎肯定他们甚至没有使用UINavigationController。这是一个带有一个或两个模型视图控制器的单视图应用程序。无论如何,我已经用一些更有趣的信息更新了我的答案。
  • 谢谢沙。最后一个问题。我已经仔细阅读了您链接的页面,但我没有理解一件事:当我们尝试在导航控制器中隐藏状态栏时,导航栏应该再次固定到 UIWindow 的顶部,它再次在视觉上是连续的, 不是?如果是,为什么导航控制器会调整其导航栏的大小?
【解决方案2】:

我不知道它是否能解决您的问题,但我使用 SWRevealViewController 项目获得了几乎相同的效果。在 appDelegate 中,我设置了此类的委托方法来执行此操作:

- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position {
#ifdef DEBUG
    NSArray *teste = @[@"FrontViewPositionLeftSideMostRemoved",@"FrontViewPositionLeftSideMost",@"FrontViewPositionLeftSide",@"FrontViewPositionLeft",@"FrontViewPositionRight",@"FrontViewPositionRightMost",@"FrontViewPositionRightMostRemoved"];
    NSLog(@"%@ %d", teste[position], position);
#endif
    if (position == FrontViewPositionRight)
        [[UIApplication sharedApplication] setStatusBarHidden:YES  withAnimation:UIStatusBarAnimationFade];
    UINavigationController *frontViewController = (id)revealController.frontViewController;
    frontViewController.navigationBar.centerY += (position == FrontViewPositionRight) ?  20 : 0; //  20 == statusbar heihgt
}

- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position {
    if (position == FrontViewPositionLeft)
        [[UIApplication sharedApplication] setStatusBarHidden:NO  withAnimation:UIStatusBarAnimationFade];
}

centerY 是 UIView 中的一个类别,它设置 center.y 而不处理设置框架变量的无聊部分。

【讨论】:

    【解决方案3】:

    在 iOS 7 中你应该如何做到这一点:

    @implementation ViewController
    {
        BOOL _hideStatusBar;
    }
    
    -(UIStatusBarStyle)preferredStatusBarStyle
    {
        return UIStatusBarStyleDefault;
    }
    
    -(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
    {
        return UIStatusBarAnimationFade;
    }
    
    -(BOOL)prefersStatusBarHidden
    {
        return _hideStatusBar;
    }
    
    -(void)setStatusBarHidden:(BOOL)hidden
    {
        [UIView animateWithDuration:1.0 animations:^{
            _hideStatusBar = hidden;
            [self setNeedsStatusBarAppearanceUpdate];
        }];
    }
    
    @end
    

    【讨论】:

    • 这会起作用,但如果您在导航栏中设置了 translucent = NO,则只有这并不能解决导航栏和子控制器向上滑动的问题。
    【解决方案4】:

    查看UIApplication 上的方法setStatusBarHidden:withAnimation:。它将允许您显示或隐藏状态栏,并且动画可以是无、淡出或滑动。您只需要添加一个调用来隐藏该栏并在正确的时间显示该栏,并决定您是否喜欢如图所示的淡入淡出,或者幻灯片是否更适合您。

    https://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/UIApplication/setStatusBarHidden:withAnimation:

    【讨论】:

    • 然后添加一个与导航栏匹配但与状态栏具有相同框架的UIView。您可能需要对时间进行一些试验才能获得您想要的效果。
    • 怎么样?如果您仔细查看 Tinder,它只会隐藏状态栏而不会弄乱新视图。您可以通过查看侧边菜单动画工作时状态栏如何淡出来了解这一点。
    【解决方案5】:

    您可以使用-setStatusBarHidden:withAnimation:,如果您在-viewDidAppear: 中调整您的视图框架,那么您将看不到任何拉伸。 请注意,自动布局已禁用。

    -(void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        CGRect frame = self.view.frame;
        // adjust root view frame 
        frame.origin.y -= 20;
        frame.size.height += 20;
    
        [self.view setFrame:frame];
    
        // adjust subviews y position
        for (UIView *subview in [self.view subviews])
        {
            CGRect frame = subview.frame;
            frame.origin.y += 20;
            [subview setFrame:frame];
        }
    }
    
    - (IBAction)sliderChanged:(id)sender
    {
        UISlider *s = (UISlider *)sender;
        if (s.value > .5)
        {
            UIApplication *app = [UIApplication sharedApplication];
            if (![app isStatusBarHidden])
                [app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
        }
        else
        {
            UIApplication *app = [UIApplication sharedApplication];
            if ([app isStatusBarHidden])
                [app setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 1970-01-01
      • 2016-02-15
      • 1970-01-01
      • 1970-01-01
      • 2015-09-17
      相关资源
      最近更新 更多