xib文件中的安全区域布局指南 - iOS 10

时间:2017-09-19 10:45:14

标签: ios ios10 xcode9 iphone-x

我开始针对iPhone X调整我的应用程序,并在Interface Builder中发现了一个问题。 根据官方Apple视频,安全区域布局指南应该向后兼容。我发现它在故事板中运行得很好。

但是在我的XIB文件中,iOS 10中没有遵守安全区域布局指南。

它们适用于新操作系统版本,但iOS 10设备似乎只是假设安全区域距离为零(忽略状态栏大小)。

我错过了所有必需的配置吗?这是一个Xcode错误,如果是这样,任何已知的解决方法?

以下是测试项目中的问题的屏幕截图(左iOS 10,右iOS 11):

safe area alignment on top of the screen

9 个答案:

答案 0 :(得分:69)

安全区域布局和向后兼容性存在一些问题。查看我对here的评论。

您可以通过其他约束解决问题,例如1000优先级> = 20.0到superview.top和750优先级== safearea.top。如果你总是显示状态栏,那应该可以解决问题。

更好的方法可能是为iOS 11之前和iOS-11及更高版本提供单独的故事板/ xib,特别是如果遇到的问题多于此问题。最好的原因是因为在iOS 11之前你应该将限制布局到顶部/底部布局指南,但是对于iOS 11,你应该将它们放到安全区域。布局指南消失了。对于iOS 11之前的布局指南,在风格上比仅仅偏移20个像素更好,即使结果与IFF相同,您总是会显示状态栏。

如果采用这种方法,您需要将每个文件设置为将在其上使用的正确部署目标(iOS 11或更早版本),以便Xcode不会向您发出警告和允许您使用布局指南或安全区域,具体取决于。在您的代码中,在运行时检查iOS 11,然后加载相应的storyboard / xibs。

这种方法的缺点是维护,(您将拥有两组视图控制器来维护和保持同步),但是一旦您的应用程序仅支持iOS 11+或Apple修复后向兼容性布局指南约束一代,你可以摆脱iOS 11之前的版本。

顺便问一下,你如何显示你看到的控制器?它只是根视图控制器还是你提出它,还是......?我注意到的问题与推送视图控制器有关,所以你可能会遇到不同的情况。

答案 1 :(得分:14)

目前,向后兼容性并不好。

我的解决方案是在界面构建器中创建2个约束,并根据您使用的ios版本删除一个:

  • for ios 11:view.top == safe area.top
  • 对于早期版本:view.top == superview.top + 20

分别将它们添加为myConstraintSAFEAREAmyConstraintSUPERVIEW的出口。然后:

override func viewDidLoad() {
    if #available(iOS 11.0, *) {
        view.removeConstraint(myConstraintSUPERVIEW)
    } else {
        view.removeConstraint(myConstraintSAFEAREA)
    }
}

答案 2 :(得分:5)

对我来说,使它在两个版本上均可使用的简单解决方法是

    if #available(iOS 11, *) {}
    else {
        self.edgesForExtendedLayout = []
    }

从文档中获得:“在iOS 10及更低版本中,使用此属性报告视图控制器的哪些边在导航栏或其他系统提供的视图下延伸。 因此,将它们设置为空数组可确保视图控制器 not 不在导航栏下方扩展。

Docu可用here

答案 3 :(得分:2)

我已经将本页中的一些答案合并到了其中,它的工作原理就像一个超级按钮(仅用于顶部布局指南,如问题所要求):

  1. 确保在故事板或xib文件中使用安全区域
  2. 将您的观点约束到安全区域
  3. 对于每个附加了view的{​​{1}}到SafeArea.top
    • constraint
    • 创建IBOutlet
    • view
    • 创建IBOutler
  4. constraint上的ViewController内部

    viewDidLoad:

编辑:

这是我在代码库中最终使用的改进版本。只需复制/粘贴下面的代码,然后将每个视图和约束连接到其IBOutletCollection。

if (@available(iOS 11.0, *)) {}
else {
    // For each view and constraint do:
    [self.view.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active = YES;
    self.constraint.active = NO;
}
  

每个IBOutletCollection的计数应相等。例如对于每个视图   应该有它的相关约束

答案 4 :(得分:0)

我最终删除了我在xib文件中的安全区域的约束。 相反,我向有问题的UIView做了一个出口,从代码我把它连接起来,在viewDidLayoutSubviews中。

let constraint = alert.viewContents.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 0)
constraint.priority = 998
constraint.isActive = true

这会引起一个小小的警报"到屏幕顶部,但确保警报内的内容视图始终低于顶部安全区域(iOS11ish)/ topLayoutGuide(iOS10ish)

简单且一次性的解决方案。如果出现问题,我会回来的。

答案 5 :(得分:0)

这也有效:

override func viewDidLoad() {
    super.viewDidLoad()

    if #available(iOS 11.0, *) {}
    else {
        view.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height - 80).isActive = true
        view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20).isActive = true
    }
}

答案 6 :(得分:0)

我添加了一个NSLayoutConstraint子类来解决此问题(IBAdjustableConstraint),它带有一个@IBInspectable变量,看起来像这样。

class IBAdjustableConstraint: NSLayoutConstraint {

    @IBInspectable var safeAreaAdjustedConstant: CGFloat = 0 {
        didSet {
            if OS.TenOrBelow {
                constant += safeAreaAdjustedConstantLegacy
            }
        }
    }
}

还有OS.TenOrBelow

struct OS {
    static let TenOrBelow = UIDevice.current.systemVersion.compare("10.9", options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
}

只需将其设置为IB中约束的子类,就可以进行

答案 7 :(得分:0)

我用过这个,添加了最安全的区域布局并与插座连接

@IBOutlet weak var topConstraint : NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()
    if !DeviceType.IS_IPHONE_X {
        if #available(iOS 11, *)  {
        }
        else{
            topConstraint.constant = 20
        }
    }
}

答案 8 :(得分:-5)

找到最简单的解决方案 - 只需停用safe area并使用topLayoutGuidebottomLayoutGuide +为iPhone X添加修复程序。也许这不是很漂亮的解决方案,但需要尽可能少的努力