仅当您使用storyboard时,iOS 9和iOS 10的Safe Areas向后兼容才有效。如果您使用xib,则没有布局指南可供回退。
https://forums.developer.apple.com/thread/87329解决方法似乎为:
(a) 将您的xib迁移到storyboard中;或者
(b) 程序上添加一些额外的约束。
如果(a)不是一个真正的选项,手动方法将会像这样:
假设您在xib中有一个视图,您希望将其保留在安全区域内(即低于任何状态栏或导航栏)。
在xib中,为您的视图和iOS 11的安全区域添加约束。将顶部约束分配给优先级750。
在您的视图控制器中添加一个属性:
@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中的限制。
如果您需要避免主页指示器,请对底部约束重复此操作。
Swift 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
}
}
}
#available(iOS 11, *)
将检查 iOS 11 及更高版本。 - PolittaNSLayoutConstraint
子类,使其更加方便使用,因为在每个可能使用该xib的视图控制器中都不需要实现任何内容。它位于此帖子的最后:https://dev59.com/NFYO5IYBdhLWcg3wMO5y#52145680 - iVentisviewDidLayoutSubviews
里而不是viewDidLoad
里? - user2378197layoutSubviews
中可能会有适用于<yourview>的布局代码,所以应该首先处理它们。我认为根据你所做的事情,viewDidLoad
也可以使用。 - Dobster自动布局
简而言之,回答你的问题是:“启用适用于 iOS 11 之前的安全区域布局指南” 您可以在项目/应用中实现安全区域布局,并将其转换为顶部和底部布局,以便与之前的 iOS 版本良好兼容。Swift 5
我只是这样做。它很简单,非常接近真实情况(只加了一个 'r')。
extension UIView {
var saferAreaLayoutGuide: UILayoutGuide {
get {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide
} else {
return self.layoutMarginsGuide
}
}
}
}
使用方式如下:
button.topAnchor.constraint(equalTo: view.saferAreaLayoutGuide.topAnchor, constant: 16)
当我在我的 UIView 中使用 Navigation Bar 并且在 iOS 10 上获得了良好的结果时,我正在使用 Objective-C 这个。如果您在 xib 中使用 SafeArea,则可以在您的 viewDidLoad
中添加:
if (@available(iOS 11.0, *)) {}
else {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
iOS 9 的处理:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBar.translucent = NO;
}
@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;
}
注意:在进行此操作时不应使用edgesForExtendedLayout属性:
self.edgesForExtendedLayout = UIRectEdgeNone;
请查看苹果文档:https://developer.apple.com/documentation/uikit/uiviewcontroller/1621515-edgesforextendedlayout
我找到了一种更方便的方法,您只需要继承固定在safeArea
上的NSLayoutConstraint
。
这种方法有点专业技巧性,因为您需要从UIView中获取ViewController,但在我看来,这是一个简单且好的替代方法,直到苹果解决Xibs中安全区向后兼容性的问题。
继承:
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:
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;
然后,我将常数值更改为该约束并刷新视图。例如,如果您使用导航栏(高度为44)以及状态栏(高度为20):
if (SYSTEM_VERSION_LESS_THAN(@"11.0")) {
_topLayoutConstraint.constant = 64;
[self.view layoutIfNeeded];
}
使用定义如下的SYSTEM_VERSION_LESS_THAN:
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)