UIView中的safeAreaInsets在iPhone X上为0

时间:2017-10-31 10:16:43

标签: ios iphone swift iphone-x

我正在更新我的应用程序以适应iPhone X.除了一个,所有视图现在都可以正常工作。我有一个视图控制器,提供覆盖整个屏幕的自定义UIView。在我使用UIScreen.main.bounds在所有布局完成之前找出视图的大小之前(我需要它来为collectionView放置正确的itemSize)。我想现在我可以做点什么了  UIScreen.main.bounds.size.height - safeAreaInsets.bottom以获得正确的可用大小。问题是,safeAreaInsets在iPhone X(模拟器)上尝试返回(0,0,0,0)。有任何想法吗?在其他视图中,我得到了safeAreaInsets的正确数字。

谢谢!

14 个答案:

答案 0 :(得分:36)

我最近有一个类似的问题,一旦触发viewDidLoad,安全区域insets将返回(0,0,0,0)。它们似乎比视图加载的其余部分稍晚设置。

我通过覆盖 viewSafeAreaInsetsDidChange 来完成它,并在其中执行我的布局:

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

答案 1 :(得分:34)

我已经找到了解决方案:我正在视图的init中执行所有实现。 safeAreaInsets在layoutSubviews()

中具有正确的大小

答案 2 :(得分:17)

我有一个视图,它是另一个视图中的子视图。 我发现我无法正确获取safeAreaInsets,它总是在iPhoneX上的那个视图中返回0,即使我把它放在layoutSubviews中。 最后的解决方案是我使用UIScreen扩展来检测safeAreaInsets,它可以像魅力一样工作。

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

        }

    }

}

答案 3 :(得分:17)

我也遇到了这个问题,试图提升视图以便为iPhone X上的键盘让路。主视图的safeAreaInsets始终为0,即使我知道子视图已经布局在这一点,因为屏幕已被绘制。我发现,如上所述,是找到keyWindow并检查其安全区域插入。

的OBJ-C:

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

夫特:

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

然后,您可以根据需要使用此值调整约束或查看框架。

答案 4 :(得分:5)

Swift iOS 11,12,13 +

var insets : UIEdgeInsets = .zero

 override func viewDidLoad() {
     super.viewDidLoad()

     insets = UIApplication.shared.delegate?.window??.safeAreaInsets ?? .zero
     //Or you can use this
     insets = self.view.safeAreaInsets
}

答案 5 :(得分:3)

在我的情况下,我在viewDidLoad()中添加了一个UICollectionView

collectionView = UICollectionView(frame: view.safeAreaLayoutGuide.layoutFrame, collectionViewLayout: createCompositionalLayout())

不幸的是,现阶段safeAreaLayoutGuide仍为零。

我通过添加以下内容解决了该问题:

override func viewDidLayoutSubviews() {
    collectionView.frame = view.safeAreaLayoutGuide.layoutFrame
}

答案 6 :(得分:2)

容器视图控制器的viewDidAppear(_ :)方法,它扩展了其嵌入式子视图控制器的安全区域,以便考虑其中的视图。

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

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

答案 7 :(得分:2)

我遇到了同样的问题。在我的情况下,在调用view.layoutIfNeeded()后,我插入的视图将正确调整大小。此后设置了view.safeAreaInsets,但只有top值是正确的。底部值仍为0(在iPhone X上)。

在尝试确定safeAreaInsets设置正确的时候,我已经在视图的safeAreaInsetsDidChange()方法中添加了一个断点。这被多次调用,但只有当我在回溯中看到CALayer.layoutSublayers()时,才能正确设置值。

所以我已经view.layoutIfNeeded()的对手CALayer替换了view.layer.layoutIfNeeded(),这导致safeAreaInsets立即正确设置,从而解决了我的问题。

<强> TL; DR

替换

view.layoutIfNeeded()

通过

view.layer.layoutIfNeeded()

答案 8 :(得分:2)

我尝试在视图控制器中使用“ self.view.safeAreaInset”。首先,当它在控制器的生命周期方法“ viewDidLoad”中使用它时,它是一个NSInsetZero,然后从网上搜索它并获得正确的答案,日志如下:

ViewController loadView() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLoad() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewWillAppear() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLayoutSubviews() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
ViewController viewDidAppear() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

因此您可以选择需要使用safeAreaInset的正确方法并使用它!

答案 9 :(得分:0)

[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero

答案 10 :(得分:0)

只需尝试self.view.safeAreaInsets而不是UIApplication.shared.keyWindow?.safeAreaInsets 通过应用程序keyWindow请求时,安全区域插图似乎无法在iOS 11.x.x设备上填充。

答案 11 :(得分:0)

在layoutSubviews或viewDidLayoutSubviews之前,不能保证视图布局。在使用这些生命周期方法之前,切勿依赖大小。如果这样做,您将得到不一致的结果。

答案 12 :(得分:0)

要计算安全区域safeAreaInsets,请尝试在viewWIllAppear()中获取它,因为在didLoad()中尚未形成视图。 您将在willAppear中获得正确的插图!

答案 13 :(得分:-1)

如果您使用自动版式,还可以选择将底部约束保持在view.safeAreaLayoutGuide.bottomAnchor上! 这样,您的布局将始终保持最新状态,而无需观察更改。