iOS 11 安全区域布局指南的向后兼容性

66

启用安全区域布局指南是否兼容 iOS 11 以下版本?

输入图片描述


6
“安全区域布局指南”的第一个谷歌搜索结果是https://useyourloaf.com/blog/safe-area-layout-guide/,其中声称*“即使您仍然针对iOS 10及更早版本,您也可以在Interface Builder中切换到使用安全区域布局指南。”* - Martin R
3
为什么要给这个问题打上 [iphone-x] 的标签? - Martin R
2
我认为我知道为什么在iPhoneX上使用tabBar时,没有安全区域Insets会出现问题。 - Yuji
4
如果你的部署目标低于iOS 9.0,Xcode会报错显示安全区域布局指南不被支持。 - rmaddy
3
有没有办法同时支持安全区域并且支持 iOS 8?我在考虑是否要在所有屏幕上通过编程的方式添加。 - Pushparaj
2
不幸的是,即使苹果声称Storyboard上的安全区域向后兼容,它实际上并不是这样,在iOS 9和10设备上会破坏你的布局。这个问题有一个radr bug。基本上,启用安全区域后,在iOS 9和10上所有视图的顶部都会有20pt的空白空间。 - Anjan Biswas
16个回答

3
在 iPhone-X 上使用 Objective-C 时,需要设置顶部和底部边距。
if (@available(iOS 11, *)) {

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                              attribute:NSLayoutAttributeBottom
                                                                              relatedBy:NSLayoutRelationEqual
                                                                                 toItem:self.parentView.safeAreaLayoutGuide
                                                                              attribute:NSLayoutAttributeBottom
                                                                             multiplier:1.0
                                                                               constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView.safeAreaLayoutGuide
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];


} else {

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                          attribute:NSLayoutAttributeBottom
                                                                          relatedBy:NSLayoutRelationEqual
                                                                             toItem:self.parentView
                                                                          attribute:NSLayoutAttributeBottom
                                                                         multiplier:1.0
                                                                           constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];

}

2

以下是我对我的项目所做的事情:

在我的情况下,我的topConstraintbottomConstraint都是@IBOutlet。这也适用于。

我的顶部和底部约束的初始配置适用于普通的iPhone,这就是为什么我只编辑iPhone X的约束。

    // iOS 11 Layout Fix. (For iPhone X)
    if #available(iOS 11, *) {
        self.topConstraint.constant = self.topConstraint.constant + self.view.safeAreaInsets.top

        self.bottomConstraint.constant = self.bottomConstraint.constant + self.view.safeAreaInsets.bottom
    }

注意:self.view 是您的超级视图,这就是我为什么在safeAreaInsets中使用它的原因。


2

如果你有一个所有视图控制器都继承的通用视图控制器,另一种解决方案是将需要调整的项目放入IBOutletCollection中,并在GenericViewController中以编程方式进行调整。这是我的代码:

@IBOutlet var adjustTopSpaceViews: [UIView]?

override func viewDidLoad() {
    super.viewDidLoad()
    adjustViews()
    ....
}

func adjustViews() {
    guard let views = adjustTopSpaceViews,
        ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11 else {
            return
    }
    let statusBarHeight = UIApplication.shared.statusBarFrame.height
    for subview in views {
        subview.superview?.constraints.filter({ (constraint) -> Bool in
            return constraint.firstAttribute == .top
                && constraint.secondAttribute == .top
                && (constraint.firstItem as? UIView == subview || constraint.secondItem as? UIView == subview)
        }).forEach({ (constraint) in
            constraint.constant += (constraint.firstItem as? UIView == subview) ? statusBarHeight : -statusBarHeight
        })
    }
}

2

我在iOS 9上使用WKWebView和安全区域时遇到了向后兼容性问题。 由于某些原因,WKWebView简单地忽略了安全区域布局设置。


你是在推送它、展示它还是它是你的应用程序的根视图? - clarus
我通过将视图框架的初始化从viewDidLoad移动到viewWillAppear来解决了这个问题。这很明显,但对于iOS 10和iOS 11并不是必需的。新的iOS版本在视图初始化后会自动选择正确的大小。 - Nik

1

这是我的iOS 9到iOS 11+解决方案包装器,使用Swift 4+编写

    let safeAreaTopAnchor:NSLayoutYAxisAnchor?
    if #available(iOS 11.0, *) {
        safeAreaTopAnchor = contentView.safeAreaLayoutGuide.topAnchor
    } else {
        // Fallback on earlier versions

        var parentViewController: UIViewController? {
            var parentVCResponder: UIResponder? = self
            while parentVCResponder != nil {
                parentVCResponder = parentVCResponder!.next
                if let viewController = parentVCResponder as? UIViewController {
                    return viewController
                }
            }
            return nil
        }

        safeAreaTopAnchor = parentViewController?.topLayoutGuide.bottomAnchor

    }

0

简单的 Swift 4 解决方案:

首先将顶部约束优先级设置为安全区域的 750,然后:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    if #available(iOS 11, *) {
        // Safe area constraints already set.
    } else {
        NSLayoutConstraint.activate([
            self.yourView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
        ])
    }
}

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