隐藏状态栏时安全区域插图发生变化 iOS 11

11

我们的应用程序在两个需要不同状态栏样式的屏幕之间转换时,将状态栏暂时隐藏作为动画的一部分。

我们有一个百分比驱动的动画过渡,当启动时,通过动画隐藏状态栏,完成后重新显示状态栏。

在iOS 11中,安全区域插图包括状态栏高度,这可能是可变的,并且当隐藏时,安全区域的顶部插图高度将下降到0高度。这会重新调整所有视图大小,导致可怕的跳跃。

尽管如此,我们仍然希望将我们的视图限制在安全区域内,因为我们正在尝试支持iPhone X。

当隐藏状态栏时,可以临时禁用对安全区域插图的更改吗?


这个问题有任何更新吗?我们现在也遇到了同样的问题,但是找不到一个好的解决方案。 - Tonny Xu
嗨Tonny,我从来没有解决它,我只是停止隐藏状态栏并立即更改颜色。 - David Rees
这个(调整 additionalSafeAreaInsets)是唯一对我有效的。你不需要去管 UIApplication 或者其他的东西! - aheze
5个回答

7

将约束设置为安全区域时,会受到状态栏以及视图在屏幕上的实际位置和变换的影响。如果您希望始终将顶部(或底部)安全区域高度应用于视图约束,则可以使用自定义约束来实现。

以下约束将自动将其 constant 值设置为设备顶部安全区域高度,不受状态栏或其他参数的影响。 要使用它,请将任何 约束的类更改为此类,并且它们的 constant 始终是安全区域高度。 请注意,在设备旋转时 ,它的值不会更改。

Objective-C

@interface TopSafeAreaContraint : NSLayoutConstraint

@end

@implementation TopSafeAreaContraint

- (void)awakeFromNib {
    [super awakeFromNib];

    if (@available(iOS 11.0, *)) {
        UIEdgeInsets insets = [UIApplication sharedApplication].keyWindow.safeAreaInsets;
        self.constant = MAX(insets.top, 20.0);
    } else {
        // Pre-iOS 11.0
        self.constant = 20.0;
    }
}

@end

Swift

class TopSafeAreaConstraint: NSLayoutConstraint {
    override func awakeFromNib() {
        super.awakeFromNib()
        if #available(iOS 11.0, *) {
            let insets = UIApplication.shared.keyWindow?.safeAreaInsets ?? .zero
            self.constant = max(insets.top, 20)
        } else {
            // Pre-iOS 11.0
            self.constant = 20.0
        }
    }
}

就是这样!我通过这个更改将此功能添加到我们的应用程序中,它运行得非常好。当safeAreaInsets.top为0时,我必须进行一次小的更改,现在它也很好地工作了。感谢您提供的好主意。 - David Rees
@DavidRees 太好了!我自己也在一些地方使用它,所以我有点好奇。你什么时候发现 safeAreaInsets.top 是0的? - LGP
1
很奇怪的是,我发现在iPhone SE、iPhone 8 Plus上,在多个应用程序中,safeAreaInsets在所有边缘上都为零。唯一不同的时候是在iPhone X上。 - David Rees
1
这对我没有用,因为我正在我的initialViewController上使用它,而在那时keyWindow仍然是nil。但是,我会点赞这个答案,因为它给了我一个解决我一直遇到的问题的想法,我将在下面的回答中概述。 - nstein

2
我一直遇到类似的问题,所以我想出了一个稍微不同的方法。这不是直接解决问题的答案,而是一个在我的情况下有效的解决方法。
我有两个不同的视图控制器,两者都必须有一个导航栏(但不需要导航控制器)。第一个视图控制器以模态方式呈现第二个视图控制器。问题是,第二个视图控制器只支持横屏,这意味着对于具有边缘到边缘显示的 iPhone,任何对prefersStatusBarHidden的覆盖都会被忽略,系统总是返回true(参见此处)。
我所做的是通过自定义视图模拟状态栏高度,然后在viewDidLoad(_:)中调整高度约束常量。

enter image description here

enter image description here

我没有看到丑陋的导航栏或视图控制器跳转。

1
获取安全区域顶部约束的引用,尝试更改该约束的常量以调整状态栏的隐藏/显示。这对我很有效,尽管在一个略有不同的情况下,我在prefersStatusBarHidden方法中设置了约束常量,以响应显示/隐藏工具栏。

1
我认为这违反了指南,因为iPhone X上的状态栏与之前的设备不是相同的固定大小。编辑:话虽如此,我不确定还有什么其他选择。如果您决定采用这种方法,您可能需要检查使用的设备并根据该决策确定常量。 - FateNuller

1
尝试添加两个约束条件:

1)视图-父视图

enter image description here

2) 视图 - 安全区域

enter image description here


1
此答案不支持iPhone X。 - David Rees
这在 iPhone X 上运行得很好,但仅当第一个约束条件(视图 - 父视图)> = 20 时。 - maxwell
1
问题在于状态栏高度包含在状态栏中。 在没有导航栏的 iPhone SE 上,safeAreaInsets.top = 20,状态栏高度 = 20 在 iPhone X 上,safeAreaInsets.top = 64,状态栏高度 = 20 当 iPhone SE 上的状态栏被隐藏时,由于约束,它不会低于 20 像素。 但是,当 iPhone X 上的状态栏被隐藏时,它将下降到 44,因为状态栏被隐藏,约束仍然得到满足,因为它超过了 20 点。因此,iPhone SE 的状态栏将保持静止,而 iPhone X 将向上移动 20 点。 - David Rees

0
通常情况下,您希望滚动视图在状态栏(安全区域)下方,并简单地调整其内容插入,而不是仅在安全区域内布局。对于UIScrollView,默认情况下会自动进行调整。请参见contentInsetAdjustmentBehavior
如果您的滚动视图具有完整的视图大小(在安全区域下方),即使滚动视图中的安全区域插入被自动修改,隐藏和显示状态栏对我来说也非常完美。

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