如何防止状态栏与UINavigationController上设置的hidesBarsOnSwipe重叠内容?

时间:2014-09-16 13:40:42

标签: ios objective-c uinavigationcontroller uinavigationbar ios8

我试图使用iOS 8中添加的新功能 - 在用户滚动表格视图时隐藏导航栏(类似于移动Safari的功能)。我在[{1}}的{​​{1}}方法中将hidesBarsOnSwipe的属性UINavigationController设置为YES

viewDidAppear

滚动视图时,导航栏会隐藏。到现在为止还挺好。但状态栏仍然可见,我的表格视图内容通过它显示,看起来很难看:

enter image description here

我尝试将UITableViewController设置为- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if([self.navigationController respondsToSelector:@selector(hidesBarsOnSwipe)]) { self.navigationController.hidesBarsOnSwipe = YES; } } 或调整表格视图的edgesForExtendedLayout,但它没有帮助。是否有其他解决方案可以隐藏状态栏和导航栏,或者使其不透明?

9 个答案:

答案 0 :(得分:39)

实际上这很容易做到。您只需要将导航isNavigationBarHidden属性与状态栏连接起来。

<强>目标C

- (BOOL)prefersStatusBarHidden {
    return self.navigationController.isNavigationBarHidden;
}

Swift&lt; = 2.3

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}

Swift 3.0

override var prefersStatusBarHidden: Bool {
    return navigationController?.isNavigationBarHidden ?? false
}

并确保您的应用程序.plist文件中有“查看基于控制器的状态栏外观”=“YES”。

答案 1 :(得分:30)

建立anas的答案,我有一个有效的解决方案(我假设tableViewController是你的UITableViewController个实例):

UINavigationController子类中(或者也可能来自tableViewController):

- (void)viewDidLoad {
    if ([self respondsToSelector:@selector(barHideOnSwipeGestureRecognizer)]) {
        // iOS 8+
        self.hidesBarsOnSwipe = YES;
        [self.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
    }
}

- (void)swipe:(UISwipeGestureRecognizer *)recognizer {
    BOOL shouldHideStatusBar = self.navigationController.navigationBar.frame.origin.y < 0;
    tableViewController.hideStatusBar = shouldHideStatusBar;
    [UIView animateWithDuration:0.2 animations:^{
        [tableViewController setNeedsStatusBarAppearanceUpdate];
    }];
}

tableViewController

@property(nonatomic, getter = shouldHideStatusBar) BOOL hideStatusBar;

- (BOOL)prefersStatusBarHidden {
    return [self shouldHideStatusBar];
}

如果这不适合你,请告诉我。一些不明显的事情:

    隐藏时
  • self.navigationController.navigationBar.frame.origin.y为-44(导航栏的负高度),可见时为20(状态栏的高度)。即使在动画期间也没有中间,所以负值==隐藏和非负值==可见。
  • 子视图控制器是查询是否应隐藏状态栏的控制器。在我的情况下,我在UIViewController内的UINavigationController内有一个UITabBarController,直到我在prefersStatusBarHidden上覆盖UIViewController后才能生效。< / LI>
  • 由于隐藏状态栏没有框架,除非您将动画块中的setNeedsStatusBarAppearanceUpdate包裹起来,否则您的内容可能会超过20分。
  • 希望语法正确;我从我的Swift代码中反向移植了这个。

答案 2 :(得分:8)

该新属性附带barHideOnSwipeGestureRecognizer

来自UINavigationController Class Reference

  

您可以根据需要更改手势识别器,但不能   更改其委托,您不能删除默认目标对象   以及配置它的动作。不要试图替换它   通过覆盖财产来识别手势。

但您可以添加目标:

[self.navigationController setHidesBarsOnSwipe:YES];
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipeGesture:)];

...并在回调中做任何你想做的事情:

- (void)swipeGesture:(UIPanGestureRecognizer*)gesture
{
    // Tweak the status bar
}

您可能需要手动打开手势状态,找出何时隐藏/显示状态栏等。希望有所帮助!

答案 3 :(得分:3)

@iOSergey的答案非常完美!

以下是 Swift 1.2中的解决方案。将以下代码添加到视图.swift文件:

override func prefersStatusBarHidden() -> Bool {

    return self.navigationController!.navigationBarHidden as Bool

}

答案 4 :(得分:3)

如果要使用动画隐藏状态栏:

override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
    return .Slide
}

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}

答案 5 :(得分:2)

经过多次努力,我终于能够解决这个问题。

  1. 将TableViewController更改为UIViewController
  2. 将TableView拖到UIViewController并将其对齐main.storyboard中导航栏下方
  3. 添加缺失的约束。
  4. 点击tableview并检查约束
  5. 将底部空间设置为:superview to 0
  6. 将尾随空格设置为superview为0
  7. 将领先空间设置为superview为0
  8. 设置&#34;将顶部对齐:顶部布局指南。顶部到0(非常重要)
  9. 将以下代码添加到UIViewController的viewDidLoad函数中:

      

    //为状态栏创建纯色背景(在Swift代码中)

         

    让statusFrame = CGRectMake(0.0,0,self.view.bounds.size.width,
      UIApplication.sharedApplication()。statusBarFrame.size.height)

         

    var statusBar = UIView(frame:statusFrame)

         

    statusBar.backgroundColor = UIColor.whiteColor()

         

    self.view.addSubview(状态栏。)

    您正在做的是在导航栏下方创建一个实心栏。当导航栏向上移动时,实心条也向上移动并且在状态栏后面。

    唯一的问题是,当您向侧面旋转屏幕时,即使状态栏消失,白色条仍然存在。

答案 6 :(得分:1)

好吧,我花了一整天的时间来做这件事,希望这可以帮助一些人。有一个barHideOnSwipeGestureRecognizer。所以你可以为相应的UIPanGesture创建一个监听器,注意如果导航栏被隐藏,那么它的y原点是-44.0;否则,它是0(不是20,因为我们隐藏了状态栏!)。

在你的视图控制器(swift 2)中:

 // Declare at beginning
var curFramePosition: Double!
var showStatusBar: Bool = true
self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")

...

override func viewDidLoad(){
    self.navigationController?.hidesBarsOnSwipe = true
  curFramePosition = 0.0 // Not hidden
  self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")
  ...
}

func didSwipe(swipe: UIPanGestureRecognizer){
    // Visible to hidden
    if curFramePosition == 0 && self.navigationController?.navigationBar.frame.origin.y == -44 {
        curFramePosition = -44
        showStatusBar = false
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
    // Hidden to visible
    else if curFramePosition == -44 && self.navigationController?.navigationBar.frame.origin.y == 0 {
        curFramePosition = 0
        showStatusBar = true
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
}

override func prefersStatusBarHidden() -> Bool {
    if showStatusBar{
        return false
    }
    return true
}

答案 7 :(得分:0)

另一种方法是添加另一个视图(在tableview或collectionview或webview或scrollview之上或其他任何视图上方)并将视图的顶部约束设置为&#34; Superview.Top&#34;及其底部约束&#34;顶部布局指南.Bottom&#34; ,设置视图的背景颜色 就是这样,你甚至可以在没有任何代码的Interface Builder中完成所有操作。 如果你想响应那个事件,你可以在视图的边界变化中添加一个keypath观察者,或者对视图进行子类化并覆盖它的边界setter ......

答案 8 :(得分:0)

您需要将导航isNavigationBarHidden属性与状态栏连接起来。

    return self.navigationController.isNavigationBarHidden;