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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46184197/
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 09:25:48  来源:igfitidea点击:

iOS 11 safe area layout guide backwards compatibility

iosswiftxcodecompatibilitysafearealayoutguide

提问by Ted

Is enabling Safe Area Layout Guides compatible to iOS below 11?

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

enter image description here

在此处输入图片说明

回答by thijsonline

I managed to work with the new Safe Area layout guides and maintain backwards compatibility with iOS 9 and iOS 10: (EDIT: as pointed out in the comments by @NickEntin, this implementation will presume there is a status bar present, which won't be true in landscape on the iPhone X. Resulting in to much space to the top (20 points). It will run perfectly fine however.

我设法使用新的安全区域布局指南并保持与 iOS 9 和 iOS 10 的向后兼容性:( 编辑:正如@NickEntin 在评论中指出的那样,此实现将假定存在状态栏,它不会在 iPhone X 的横向上确实如此。导致顶部有很多空间(20 分)。但是它会运行得非常好。

E.g. if you want a view to be 10 points below the status bar (and 10 points below the sensor housing on iPhone X):

例如,如果您希望视图位于状态栏下方 10 点处(以及 iPhone X 传感器外壳下方 10 点处):

  1. In your XIB, go to File Inspectorand enable the safe are by checking Use Safe Area Layout Guides.
  2. Create a constraint from the view's top to the main view's top, with >=(greater than or equal) constraint, constant 30(30 because we want 10 points spacing to the status bar which is 20 points high) and priority High(750).
  3. Create a constraint from the view's top to the Safe Area's top, with =(equal) constraint, constant 10and priority Low(250).
  1. 在您的 XIB 中,File Inspector通过选中Use Safe Area Layout Guides.
  2. 创建一个从视图顶部到主视图顶部的>=约束,具有(大于或等于)约束、常量30(30,因为我们希望与状态栏有 10 点间距,即 20 点高)和优先级High(750)。
  3. 创建从视图顶部到安全区域顶部的=约束,具有(相等)约束、常量10和优先级Low(250)。

The same can be done for a view at the bottom (and for leading/trailing or left/right to the Safe Area):

对于底部的视图(以及安全区域的前/后或左/右)也可以这样做:

  1. In your XIB, go to File Inspectorand enable the safe are by checking Use Safe Area Layout Guides.
  2. Create a constraint from the view's bottom to the main view's bottom, with >=(greater than or equal) constraint, constant 10and priority High(750).
  3. Create a constraint from the view's bottom to the Safe Area's bottom, with =(equal) constraint, constant 10and priority Low(250).
  1. 在您的 XIB 中,File Inspector通过选中Use Safe Area Layout Guides.
  2. 创建从视图底部到主视图底部的>=约束,具有(大于或等于)约束、常量10和优先级High(750)。
  3. 创建从视图底部到安全区域底部的=约束,具有(相等)约束、常量10和优先级Low(250)。

回答by Dobster

The backwards compatibility of Safe Areas for iOS 9 & iOS 10 only works if you are using storyboards. If you are using xibs, there is no layout guide to fall back to. https://forums.developer.apple.com/thread/87329

iOS 9 和 iOS 10 安全区域的向后兼容性仅在您使用故事板时才有效。如果您使用的是 xibs,则没有可回退的布局指南。 https://forums.developer.apple.com/thread/87329

The workarounds seem to be either

解决方法似乎是

(a) migrate your xibs into storyboards, or

(a) 将您的 xib 迁移到故事板,或

(b) add some additional constraints programmatically.

(b) 以编程方式添加一些额外的约束。

If (a) is not really an option, the manual approach will be something like this:

如果 (a) 不是一个真正的选项,手动方法将是这样的:

Assuming you have a view in your xib that you want to keep within the safe area (i.e. below any status bar or navigation bar).

假设您的 xib 中有一个视图,您希望将其保留在安全区域内(即在任何状态栏或导航栏下方)。

  1. Add constraints in your xib between your view and the safe area for iOS 11. Assign the top constraint to a priority of 750.

    add a top constraint

  2. In your view controller, add a property:

    @property (nonatomic, strong) NSLayoutConstraint *topLayoutConstraint;
    

    And then in viewDidLayoutSubviews:

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        if (@available(iOS 11, *)) {
            // safe area constraints already set
        }
        else {
            if (!self.topLayoutConstraint) {
                self.topLayoutConstraint = [self.<yourview>.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor];
                [self.topLayoutConstraint setActive:YES];
            }
        }
    }
    

    The new constraint will only be created for iOS 9 & iOS 10, has a default priority of 1000, and overrides the one in the xib.

  3. Repeat for a bottom constraint if you need to avoid the home indicator.

  1. 在您的视图和 iOS 11 的安全区域之间的 xib 中添加约束。将顶部约束分配给 750 的优先级。

    添加顶部约束

  2. 在您的视图控制器中,添加一个属性:

    @property (nonatomic, strong) NSLayoutConstraint *topLayoutConstraint;
    

    然后在 viewDidLayoutSubviews 中:

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        if (@available(iOS 11, *)) {
            // safe area constraints already set
        }
        else {
            if (!self.topLayoutConstraint) {
                self.topLayoutConstraint = [self.<yourview>.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor];
                [self.topLayoutConstraint setActive:YES];
            }
        }
    }
    

    新约束只会为 iOS 9 和 iOS 10 创建,默认优先级为 1000,并覆盖 xib 中的优先级。

  3. 如果您需要避开主页指示器,请重复底部约束。

Swift 4 version:

斯威夫特 4 版本:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if #available(iOS 11, *) {
        // safe area constraints already set
    } else {
        if topLayoutConstraint == nil {
            topLayoutConstraint = <yourview>.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
            topLayoutConstraint?.isActive = true
        }
    }
}

回答by clarus

There's definitely at least one backwards compatibility issue with iOS 11's safe area constraints that I've observed in the Xcode 9 GM--pushed view controllers with safe area constraints.

我在 Xcode 9 GM 中观察到,iOS 11 的安全区域约束肯定至少存在一个向后兼容性问题——推送具有安全区域约束的视图控制器。

If your navigation bar is hidden and you push a safe area top-constrained view, the pushed view will overlap the status bar on iOS 9 & 10.

如果您的导航栏被隐藏并且您推送安全区域顶部约束视图,则推送的视图将与 iOS 9 和 10 上的状态栏重叠。

If the navigation bar is visible, and "under top bars" disabled, the pushed view will still slide up under the nav bar to get to the top of the screen. The navigation bar is placed correctly.

如果导航栏可见,并且禁用了“顶栏下方”,则推送的视图仍会在导航栏下方向上滑动以到达屏幕顶部。导航栏放置正确。

On iOS 11, the layout will be correct in both cases.

在 iOS 11 上,两种情况下的布局都是正确的。

Here's a simple example: http://www.filedropper.com/foobar

这是一个简单的例子:http: //www.filedropper.com/foobar

And here's a video of it w/nav bar hidden (iOS 10.3 on left, iOS 11 on right): https://vimeo.com/234174841/1e27a96a87

这是一个隐藏导航栏的视频(左侧为 iOS 10.3,右侧为 iOS 11):https: //vimeo.com/234174841/1e27a96a87

Here's a version where the nav bar is visible (enabled in the nib): https://vimeo.com/234316256/f022132d57

这是导航栏可见的版本(在笔尖中启用):https: //vimeo.com/234316256/f022132d57

I filed this as Radar #34477706.

我将此作为 Radar #34477706 提交。

Thanks to @Sanderfor pointing out the nav bar visible case.

感谢@Sander指出导航栏可见的情况。

回答by Krunal

Yes, your project/app will work in iOS versions prior to iOS 11 without any issue. In iOS versions prior to 11, it replaces/considers Safe Area Layout into normal AutoLayout and follows Rules of Top and Bottom layout guide.

是的,您的项目/应用程序可以在 iOS 11 之前的 iOS 版本中正常运行,不会出现任何问题。在 iOS 11 之前的版本中,它将安全区域布局替换/考虑为正常的自动布局,并遵循顶部和底部布局指南的规则。

I tested my existing project with and without 'SafeAreaLayout' on both platforms (iOS 11 and backward iOS 10). It's working fine.

我在两个平台(iOS 11 和落后的 iOS 10)上使用和不使用“SafeAreaLayout”测试了我现有的项目。它工作正常。

Just make sure:

  • If you have designed your project/User Interface in AutoLayout; constraints of your UIElement follows/relative to Top and Bottom layout guide (not to superview). So by a single click (enable) on SafeAreaLayout option, will automatically implement SafeArea layout properly for all Interface Builders files in your storyboard.

  • If you have designed your project/User Interface in SafeAreaLayout; then it will automatically follow Top and Bottom layout guide in backward iOS.

只要确保:

  • 如果您在 AutoLayout 中设计了您的项目/用户界面;UIElement 的约束遵循/相对于顶部和底部布局指南(而不是超级视图)。因此,通过单击(启用) SafeAreaLayout 选项,将自动为故事板中的所有 Interface Builders 文件正确实现 SafeArea 布局。

  • 如果您在 SafeAreaLayout 中设计了您的项目/用户界面;然后它将自动遵循落后的 iOS 中的顶部和底部布局指南。

Here is sample snapshot with result, By enabling or disabling Safe Area layout, won't effect on existing design.

这是带有结果的示例快照,通过启用或禁用安全区域布局,不会影响现有设计。

Safe Area Layout:enter image description here

安全区布局:在此处输入图片说明

AutoLayout

自动布局

enter image description here

在此处输入图片说明

In short, an answer to your question is: "Enabling Safe Area Layout Guides compatible to iOS prior to 11"

You can implement Safe Area Layout in your project/app and it will work fine with previous iOS versions by converting Safe Area Layout into Top and Bottom Layout.

简而言之,您的问题的答案是:“启用与 iOS 11 之前兼容的安全区域布局指南”

您可以在您的项目/应用程序中实现安全区域布局,通过将安全区域布局转换为顶部,它可以在以前的 iOS 版本中正常工作和底部布局。

回答by ihar

If you use xibs without storyboard then they don't have layout guides on ios 10. So move xib to storyboard to have backward compatibility.

如果您使用没有故事板的 xib,那么它们在 ios 10 上没有布局指南。因此,将 xib 移至故事板以获得向后兼容性。

回答by Dmitry A.

I was using this in Objective-C with good result for iOS 10. In case you use SafeArea in your xib then you may add in your viewDidLoad:

我在 Objective-C 中使用它,在 iOS 10 中取得了不错的结果。如果您在 xib 中使用 SafeArea,那么您可以添加viewDidLoad

if (@available(iOS 11.0, *)) {}
else {
    self.edgesForExtendedLayout = UIRectEdgeNone;
}

回答by Mads Buus

Swift 5

斯威夫特 5

I just do this. It is simple and very close to the real thing (just added an 'r').

我只是这样做。它很简单,非常接近真实的东西(只是添加了一个“r”)。

extension UIView {
var saferAreaLayoutGuide: UILayoutGuide {
    get {
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide
        } else {
            return self.layoutMarginsGuide
        }
    }
}

Use like this:

像这样使用:

button.topAnchor.constraint(equalTo: view.saferAreaLayoutGuide.topAnchor, constant: 16)

回答by Fatih Aksu

for iOS 9:

对于 iOS 9:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    self.navigationController.navigationBar.translucent = NO;
}

if you enable autolayoutand add view constraints to the safe area, you are good to go above iOS 11+, but it may not work well with iOS 9and your view may appear under your navigation bar. To solve this problem, you can disable translucentattribute in 'viewWillAppear:(BOOL)animated'method.

如果您启用自动布局并将视图约束添加到安全区域,那么您可以使用iOS 11+以上的版本,但它可能不适用于iOS 9,并且您的视图可能会出现在导航栏下方。为了解决这个问题,你可以在' viewWillAppear:(BOOL)animated'方法中禁用半透明属性。

To not to break previous state of translucentattribute of your navigation bar, you should keep previous value and re-set it in 'viewWillDisappear:(BOOL)animated'

为了不破坏导航栏半透明属性的先前状态,您应该保留先前的值并在' viewWillDisappear:(BOOL)animated'中重新设置它

@interface YourViewController ()
@property (nonatomic, assign) BOOL translucentState;
@end

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    self.translucentState = self.navigationController.navigationBar.translucent;
    self.navigationController.navigationBar.translucent = NO;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    self.navigationController.navigationBar.translucent = self.translucentState;
}

P.S.should not use edgesForExtendedLayoutwith doing this:

PS不应该使用edgeForExtendedLayout这样做:

self.edgesForExtendedLayout = UIRectEdgeNone;

Check out Apple documentation: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621515-edgesforextendedlayout

查看 Apple 文档:https: //developer.apple.com/documentation/uikit/uiviewcontroller/1621515-edgesforextendedlayout

回答by iVentis

I found a more convenient way where you only need to subclass the NSLayoutConstraintthat is pinned to your safeArea.

我找到了一种更方便的方法,您只需要将NSLayoutConstraint固定到您的safeArea.

It's kinda hacky since you have to get the ViewController from a UIView but in my opinion, that's an easy and good alternative until Apple finally fixes backward compatibility for the safeArea in Xibs.

这有点棘手,因为您必须从 UIView 获取 ViewController 但在我看来,这是一个简单而好的替代方案,直到 Apple 最终修复了 Xibs 中 safeArea 的向后兼容性。

Subclass:

子类:

class SafeAreaBackwardsCompatabilityConstraint: NSLayoutConstraint {
private weak var newConstraint: NSLayoutConstraint?

override var secondItem: AnyObject? {
    get {
        if #available(iOS 11.0, *) {}
        else {
            if let vc = (super.secondItem as? UIView)?.parentViewController, newConstraint == nil {
                newConstraint = (self.firstItem as? UIView)?.topAnchor.constraint(equalTo: vc.topLayoutGuide.bottomAnchor)
                newConstraint?.isActive = true
                newConstraint?.constant = self.constant
            }
        }
        return super.secondItem
    }
}

override var priority: UILayoutPriority {
    get {
        if #available(iOS 11.0, *) { return super.priority }
        else { return 750 }
    }
    set { super.priority = newValue }
}
}

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

Xib:

西布:

enter image description here

在此处输入图片说明

回答by gduh

"safe area layout guide" is backward compatible. Well, unless you use it in xib. With storyboard it seems ok.

“安全区域布局指南”向后兼容。好吧,除非你在 xib 中使用它。使用故事板似乎没问题。

I solved my problem by accessing the "Top layout constraint" from the first object at the top of my view.

我通过从视图顶部的第一个对象访问“顶部布局约束”解决了我的问题。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

then, I changed the Constant value to that constraint and refresh the view. For example, if you use a navigation bar (44 height) plus the status bar (20 height) :

然后,我将 Constant 值更改为该约束并刷新视图。例如,如果您使用导航栏(44 高)加上状态栏(20 高):

if (SYSTEM_VERSION_LESS_THAN(@"11.0")) {
    _topLayoutConstraint.constant = 64;
    [self.view layoutIfNeeded];
}

With SYSTEM_VERSION_LESS_THAN which is defined like that :

SYSTEM_VERSION_LESS_THAN 定义如下:

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)