关于ios:UIView中的safeAreaInsets在iPhone X上为0

safeAreaInsets in UIView is 0 on an iPhone X

我正在更新我的应用程序以适应iPhone X。除了一个视图,所有视图现在都可以正常工作。我有一个视图控制器,它提供了一个覆盖整个屏幕的自定义uiview。在我使用UIScreen.main.bounds在完成所有布局之前找出视图的大小之前(我需要它为CollectionView放置正确的项大小)。我想现在我可以做一些像UIScreen.main.bounds.size.height - safeAreaInsets.bottom以获得正确的可用尺寸。问题是,在iPhoneX(模拟器)上尝试安全区域插入返回(0,0,0,0)。有什么想法吗?在其他视图中,我得到了正确的安全区域插入编号。

谢谢您!


我最近遇到了一个类似的问题,即一旦触发viewdidload,安全区域插入将返回(0,0,0,0)。似乎它们的设置比视图加载的其余部分要晚一些。

我通过重写VIEWSAFEAREAinsetsDidChange并在其中进行布局来绕过它:

1
2
3
override func viewSafeAreaInsetsDidChange() {
 // ... your layout code here
}


我已经找到了解决方案:我在init视图中进行了所有的实现。安全区域插入在layoutSubviews()中的大小正确。


我也遇到过这个问题,我试图向上移动视图,以便为iPhone X上的键盘让路。主视图的安全区域插入始终为0,即使我知道子视图在屏幕绘制时已在此时展开。正如上面提到的,我发现的一项工作是取下钥匙窗并检查它的安全区域插入。

Obj-C:

1
CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;

Swift:

1
let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom

然后,可以根据需要使用该值调整约束或视图框架。


我有一个视图,它是另一个视图中的子视图。我发现我不能正确地插入安全区域,它总是返回0,在iphonex上的那个视图中,即使我把它放在layoutSubview中。最后的解决方案是,我使用以下uiscreen扩展来检测安全区域插入,它可以像一个符咒一样工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
extension UIScreen {

    func widthOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let leftInset = rootView.safeAreaInsets.left

            let rightInset = rootView.safeAreaInsets.right

            return rootView.bounds.width - leftInset - rightInset

        } else {

            return rootView.bounds.width

        }

    }

    func heightOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let topInset = rootView.safeAreaInsets.top

            let bottomInset = rootView.safeAreaInsets.bottom

            return rootView.bounds.height - topInset - bottomInset

        } else {

            return rootView.bounds.height

        }

    }

}


我也遇到了同样的问题。在我的例子中,我插入的视图在调用view.layoutIfNeeded()后大小会正确。在此之后设置了view.safeAreaInsets,但只有top值是正确的。最低值仍然是0(在iPhoneX上)。

在试图找出safeAreaInsets正确设置的点时,我在视图的safeAreaInsetsDidChange()方法上添加了一个断点。这被多次调用,但只有当我在backtrace中看到CALayer.layoutSublayers()时,该值才被正确设置。

所以我把view.layoutIfNeeded()换成了CALayer的对应view.layer.layoutIfNeeded(),这就使得safeAreaInsets被正确设置,从而解决了我的问题。

DR

替换

1
view.layoutIfNeeded()

通过

1
view.layer.layoutIfNeeded()


容器视图控制器的viewDidAppear(1;:)方法,它扩展了其嵌入子视图控制器的安全区域,以说明中的视图。

在此方法中进行修改,因为在将视图添加到视图层次结构之前,视图的安全区域插入不准确。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
override func viewDidAppear(_ animated: Bool) {

   if (@available(iOS 11, *)) {

     var newSafeArea = view.safeAreaInsets

     // Adjust the safe area to accommodate
     //  the width of the side view.

     if let sideViewWidth = sideView?.bounds.size.width {
        newSafeArea.right += sideViewWidth
     }

    // Adjust the safe area to accommodate
    //  the height of the bottom view.
    if let bottomViewHeight = bottomView?.bounds.size.height {
       newSafeArea.bottom += bottomViewHeight
    }

    // Adjust the safe area insets of the
    //  embedded child view controller.
    let child = self.childViewControllers[0]
    child.additionalSafeAreaInsets = newSafeArea
  }
}


只需尝试self.view.safeAreaInsets,而不是UIApplication.shared.keyWindow?.safeAreaInsets当通过应用程序密钥窗口请求时,iOS 11.x.x设备上的安全区域插入似乎没有填充。


1
[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero

如果使用自动布局,您还可以选择将底部约束粘贴到view.safeAreaLayoutGuide.bottomAnchor!您的布局将不断更新,无需观察变化。