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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25870382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:29:53  来源:igfitidea点击:

How to prevent status bar from overlapping content with hidesBarsOnSwipe set on UINavigationController?

iosobjective-cuinavigationcontrolleruinavigationbarios8

提问by Micha? Ciuba

I'm trying to use the new feature added in iOS 8 - hiding the navigation bar while user is scrolling the table view (similar to what mobile Safari does). I'm setting the property hidesBarsOnSwipeof UINavigationControllerto YESin viewDidAppearmethod of UITableViewController:

我正在尝试使用 iOS 8 中添加的新功能 - 在用户滚动表格视图时隐藏导航栏(类似于移动 Safari 所做的)。我设置的财产hidesBarsOnSwipeUINavigationController,以YESviewDidAppear的方法UITableViewController

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

The navigation bar hides when the view is being scrolled. So far so good. But the status bar is still visible and my table view contents show through it, which looks ugly:

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

enter image description here

在此处输入图片说明

I tried setting edgesForExtendedLayoutto UIEdgeRectNoneor adjusting the contentInsetof the table view, but it didn't help. Is there any other solution to hide the status bar along with the navigation bar, or make it opaque?

我试着设置edgesForExtendedLayoutUIEdgeRectNone或调节contentInset表视图,但它并没有帮助。是否有其他解决方案可以将状态栏与导航栏一起隐藏或使其不透明?

采纳答案by Andrew

Building off of anas' answer, I have a working solution (I'm assuming tableViewControlleris your UITableViewControllerinstance):

根据 anas 的回答,我有一个可行的解决方案(我假设tableViewController是您的UITableViewController实例):

In a UINavigationControllersubclass (or also potentially from tableViewController):

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];
    }];
}

In your tableViewController:

在您的tableViewController

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

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

Let me know if this doesn't work for you. A few non-obvious things:

如果这对您不起作用,请告诉我。一些不明显的事情:

  • self.navigationController.navigationBar.frame.origin.ywas -44 (the negative height of the navigation bar) when hidden, and 20 (the height of the status bar) when visible. There was no in-between, even during animations, so a negative value == hidden and a nonnegative value == visible.
  • The child view controller is the one queried for whether or not the status bar should be hidden. In my case, I have a UIViewControllerwithin a UINavigationControllerwithin a UITabBarController, and it didn't work until I overrode prefersStatusBarHiddenon the UIViewController.
  • Since a hidden status bar has no frame, your content might jerk upwards 20 points unless you wrap the call to setNeedsStatusBarAppearanceUpdatein an animation block.
  • Hopefully the syntax is correct; I backported this from my Swift code.
  • self.navigationController.navigationBar.frame.origin.y隐藏时为 -44(导航栏的负高度),可见时为 20(状态栏的高度)。没有中间,即使在动画期间,所以负值 == 隐藏和非负值 == 可见。
  • 子视图控制器是查询状态栏是否应该隐藏的控制器。就我而言,我有一个UIViewControllerUINavigationController内的UITabBarController,直到我推翻它不工作prefersStatusBarHiddenUIViewController
  • 由于隐藏状态栏没有框架,除非您将调用包装setNeedsStatusBarAppearanceUpdate在动画块中,否则您的内容可能会向上跳动 20 点。
  • 希望语法正确;我从我的 Swift 代码向后移植了这个。

回答by iOSergey

Actually it is pretty easy to do. You just need to connect navigation isNavigationBarHidden property with status bar.

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

Objective-C

目标-C

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

Swift <= 2.3

斯威夫特 <= 2.3

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

Swift 3.0

斯威夫特 3.0

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

And be sure you have "View controller-based status bar appearance" = "YES" in your application .plist file.

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

回答by Anas

That new property comes with its barHideOnSwipeGestureRecognizer.

该新属性随其barHideOnSwipeGestureRecognizer.

From the UINavigationController Class Reference:

UINavigationController 类参考

You can make changes to the gesture recognizer as needed but must not change its delegate and you must not remove the default target object and action that come configured with it. Do not try to replace this gesture recognizer by overriding the property.

您可以根据需要更改手势识别器,但不得更改其委托,并且不得删除随其配置的默认目标对象和操作。不要试图通过覆盖该属性来替换此手势识别器。

But you can adda target:

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

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

... and do whatever you want in the callback:

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

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

You might have to manually switch on the gesture states, figure out when to hide/show the status bar, etc. Hope that helps!

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

回答by Bengger Applications

The answer from @iOSergey works perfect!

来自@iOSergey 的答案完美无缺!

Here is the solution in Swift1.2. Add the following code to the views .swift file:

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

override func prefersStatusBarHidden() -> Bool {

    return self.navigationController!.navigationBarHidden as Bool

}

回答by Tai Le

If you want to hide status bar with animation:

如果要隐藏带有动画的状态栏:

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

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

回答by John Chen

After much struggle, I was finally able to solve this.

经过一番挣扎,我终于能够解决这个问题。

  1. Change TableViewController to UIViewController
  2. Drag a TableView to the UIViewController and align it right underneath the navigation bar in the main.storyboard
  3. Add missing constraints.
  4. click on tableview and inspect the constraints
  5. set bottom space to: superview to 0
  6. set trailing space to superview to 0
  7. set leading space to superview to 0
  8. set "Align Top to: Top Layout Guide.Top to 0 (Very Important)
  1. 将 TableViewController 更改为 UIViewController
  2. 将 TableView 拖到 UIViewController 并将其对齐在 main.storyboard 中的导航栏下方
  3. 添加缺少的约束。
  4. 单击 tableview 并检查约束
  5. 将底部空间设置为:superview 为 0
  6. 将尾随空间设置为 superview 为 0
  7. 将前导空间设置为 superview 为 0
  8. 设置“将顶部对齐到:顶部布局指南。顶部到 0(非常重要)”

Add the following code to the UIViewController's viewDidLoad function:

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

// Create a solid color background for the status bar (in Swift Code)

let 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(statusBar)

// 为状态栏创建纯色背景(在 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(statusBar)

What you are doing is creating a solid bar right beneath the navigation bar. As the navigation bar moves up, the solid bar move up too and right behind the status bar.

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

The only problem is that when you rotate the screen side ways, the white bar still there even though the status bar disappears.

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

回答by goodcow

Okay I spent all day doing this, hopefully this helps some people out. There's a barHideOnSwipeGestureRecognizer. So you could make a listener for the corresponding UIPanGesture, noting that if the navigation bar is hidden then its y origin is -44.0; otherwise, it's 0 (not 20 because we hid the status bar!).

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

In your view controller (swift 2):

在您的视图控制器(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
}

回答by Abhinandan Pratap

You need to connect navigation isNavigationBarHidden property with status bar.

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

    return self.navigationController.isNavigationBarHidden;

回答by Oleg Sherman

Another way to do it is just add another view (above the tableview or collectionview or webview or scrollview or whatever) and set the view's top constraint to "Superview.Top" and its bottom constraint to "Top Layout Guide.Bottom" ,set the view's background color and thats it , you can even do it all in Interface Builder without any code. And if you want to respond to that event you can add a keypath observer to the view's bounds change , or subclass the view and override its bounds setter...

另一种方法是添加另一个视图(在 tableview 或 collectionview 或 webview 或 scrollview 或其他之上)并将视图的顶部约束设置为“Superview.Top”并将其底部约束设置为“Top Layout Guide.Bottom”,设置视图的背景颜色就是这样,您甚至可以在没有任何代码的情况下在 Interface Builder 中完成所有操作。如果您想响应该事件,您可以向视图的边界更改添加一个关键路径观察者,或者将视图子类化并覆盖其边界设置器...