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

我正在尝试使用iOS 8中添加的新function – 在用户滚动表格视图时隐藏导航栏(类似于移动Safari)。 我在UITableViewController viewDidAppear方法hidesBarsOnSwipe UINavigationController的属性hidesBarsOnSwipe设置为YES

 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if([self.navigationController respondsToSelector:@selector(hidesBarsOnSwipe)]) { self.navigationController.hidesBarsOnSwipe = YES; } } 

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

在这里输入图像说明

我尝试设置edgesForExtendedLayoutUIEdgeRectNone或调整表视图的contentInset ,但它没有帮助。 有没有其他的解决scheme,以隐藏状态栏与导航栏,或使其不透明?

build立closures的答案,我有一个工作的解决scheme(我假设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(状态栏的高度)。 即使在animation过程中也没有,所以负值==隐藏,非负值==可见。
  • 子视图控制器是查询状态栏是否应该隐藏的一个。 在我的情况下,我在UITabBarControllerUINavigationController有一个UIViewController ,它不工作,直到我覆盖UIViewController上的prefersStatusBarHidden
  • 由于隐藏状态栏没有框架,因此除非将调用setNeedsStatusBarAppearanceUpdate包装到animation块中,否则您的内容可能会向上抖动20个点。
  • 希望语法是正确的; 我从我的Swift代码中支持这个。

其实这很容易做到。 你只需要连接导航isNavigationBarHidden属性与状态栏。

Objective-C的

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

Swift <= 2.3

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

Swift 3.0

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

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

这个新的属性带有barHideOnSwipeGestureRecognizer

从UINavigationController类参考 :

您可以根据需要对手势识别器进行更改,但不得更改其委托,并且不得删除默认的目标对象和与之configuration的操作。 不要试图通过重写属性来replace这个手势识别器。

但是你可以添加一个目标:

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

…在callback中做任何你想做的事情:

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

你可能不得不手动切换手势状态,找出何时隐藏/显示状态栏,等等。希望有帮助!

@iOSergey的答案非常完美!

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

 override func prefersStatusBarHidden() -> Bool { return self.navigationController!.navigationBarHidden as Bool } 

如果你想隐藏状态栏与animation:

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

经过很多的斗争,我终于能够解决这个问题。

  1. 将TableViewController更改为UIViewController
  2. 将一个TableView拖到UIViewController中,并将其右alignment在main.storyboard的导航栏下方
  3. 添加缺less的约束。
  4. 点击tableview并检查约束
  5. 设置底部空间为:superview为0
  6. 将尾随空间设置为超级查看为0
  7. 将领导空间设置为0
  8. 设置“顶部alignment:顶部布局指南。顶部到0(非常重要)

将下面的代码添加到UIViewController的viewDidLoad函数中:

//为状态栏创build纯色背景(在Swift Code中)

让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(状态栏。)

你正在做的是在导航栏下方创build一个实心栏。 随着导航栏向上移动,实心栏也向上移动,并位于状态栏的后面。

唯一的问题是,当你旋转屏幕的方式,即使状态栏消失,白条仍然在那里。

好吧,我整天都在这样做,希望这可以帮助一些人。 有一个barHideOnSwipeGestureRecognizer 。 所以你可以为相应的UIPanGesture创build一个监听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 } 

另一种方法是添加另一个视图(在tableview或collectionview或webview或scrollview之上),并将视图的顶部约束设置为“Superview.Top”,将其底部约束设置为“Top Layout Guide.Bottom”,设置视图的背景颜色,多数民众赞成,你甚至可以在界面生成器没有任何代码。 如果你想响应这个事件,你可以添加一个keypath观察者到视图的边界改变,或者子视图,并覆盖它的边界setter …

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

  return self.navigationController.isNavigationBarHidden;