safeAreaLayoutGuide - 横向模式
safeAreaLayoutGuide - landscape mode
我已经这样设置了 safeAreaLayoutGuide:
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
topControls.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0)
])
效果很好。但是,当我将设备旋转到横向模式时,没有状态栏(电池、信号等)并且屏幕顶部的偏移量为零。这是正确的,基于锚点。然而,它看起来并不好。如何在创建锚点期间为景观添加偏移量 20?我不想手动更改基于方向的常量。
假设您 运行 在 iPhone 上,那么这是预期的行为,可以通过覆盖以下内容来更改:
override var prefersStatusBarHidden: Bool {
return false
}
根据该 UIViewController 方法的描述:
By default, this method returns false with one exception. For apps
linked against iOS 8 or later, this method returns true if the view
controller is in a vertically compact environment.
如果您覆盖它,那么您将获得一个横向状态栏,并且安全区域指南将相应地进行调整。
编辑
所以对原来的要求有点误解。不是显示状态栏而是像有状态栏一样有个空隙
这需要手动完成,因为您无法手动设置仅适用于某些 orientations/size class 的约束。
这是一个基本的 UIViewController,可以满足您的需求:
class ViewController: UIViewController {
var testView: UIView!
var landscapeConstraint: NSLayoutConstraint!
var portraitConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.testView = UIView()
self.testView.backgroundColor = .green
self.view.addSubview(self.testView)
self.testView.translatesAutoresizingMaskIntoConstraints = false
let guide = view.safeAreaLayoutGuide
self.testView.leftAnchor.constraint(equalTo: guide.leftAnchor, constant: 0).isActive = true
self.testView.rightAnchor.constraint(equalTo: guide.rightAnchor, constant: 0).isActive = true
self.testView.bottomAnchor.constraint(equalTo: guide.bottomAnchor, constant: 0).isActive = true
self.portraitConstraint = self.testView.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0)
self.landscapeConstraint = self.testView.topAnchor.constraint(equalTo: guide.topAnchor, constant: 20) // Hardcoded the size but this can be anything you want.
switch self.traitCollection.verticalSizeClass {
case .compact:
self.landscapeConstraint.isActive = true
case.regular:
self.portraitConstraint.isActive = true
default: // This shouldn't happen but let's assume regular (i.e. portrait)
self.portraitConstraint.isActive = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
switch newCollection.verticalSizeClass {
case .compact:
self.portraitConstraint.isActive = false
self.landscapeConstraint.isActive = true
case.regular:
self.landscapeConstraint.isActive = false
self.portraitConstraint.isActive = true
default: // This shouldn't happen but let's assume regular (i.e. portrait)
self.landscapeConstraint.isActive = false
self.portraitConstraint.isActive = true
}
}
}
基本上你设置了固定的约束,即左、右和底部,然后设置纵向和横向的约束(常规和紧凑的垂直尺寸 class),这两个约束在默认情况下都是禁用的。
然后你根据当前orientation/sizeclass决定激活哪一个。
然后你覆盖:
willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
基于新orientation/sizeclass.
的两个约束的方法和swap active state
需要注意的一件事是始终先停用约束,然后再激活约束以避免任何抱怨无法满足的约束。
我已经这样设置了 safeAreaLayoutGuide:
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
topControls.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0)
])
效果很好。但是,当我将设备旋转到横向模式时,没有状态栏(电池、信号等)并且屏幕顶部的偏移量为零。这是正确的,基于锚点。然而,它看起来并不好。如何在创建锚点期间为景观添加偏移量 20?我不想手动更改基于方向的常量。
假设您 运行 在 iPhone 上,那么这是预期的行为,可以通过覆盖以下内容来更改:
override var prefersStatusBarHidden: Bool {
return false
}
根据该 UIViewController 方法的描述:
By default, this method returns false with one exception. For apps linked against iOS 8 or later, this method returns true if the view controller is in a vertically compact environment.
如果您覆盖它,那么您将获得一个横向状态栏,并且安全区域指南将相应地进行调整。
编辑
所以对原来的要求有点误解。不是显示状态栏而是像有状态栏一样有个空隙
这需要手动完成,因为您无法手动设置仅适用于某些 orientations/size class 的约束。
这是一个基本的 UIViewController,可以满足您的需求:
class ViewController: UIViewController {
var testView: UIView!
var landscapeConstraint: NSLayoutConstraint!
var portraitConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.testView = UIView()
self.testView.backgroundColor = .green
self.view.addSubview(self.testView)
self.testView.translatesAutoresizingMaskIntoConstraints = false
let guide = view.safeAreaLayoutGuide
self.testView.leftAnchor.constraint(equalTo: guide.leftAnchor, constant: 0).isActive = true
self.testView.rightAnchor.constraint(equalTo: guide.rightAnchor, constant: 0).isActive = true
self.testView.bottomAnchor.constraint(equalTo: guide.bottomAnchor, constant: 0).isActive = true
self.portraitConstraint = self.testView.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0)
self.landscapeConstraint = self.testView.topAnchor.constraint(equalTo: guide.topAnchor, constant: 20) // Hardcoded the size but this can be anything you want.
switch self.traitCollection.verticalSizeClass {
case .compact:
self.landscapeConstraint.isActive = true
case.regular:
self.portraitConstraint.isActive = true
default: // This shouldn't happen but let's assume regular (i.e. portrait)
self.portraitConstraint.isActive = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
switch newCollection.verticalSizeClass {
case .compact:
self.portraitConstraint.isActive = false
self.landscapeConstraint.isActive = true
case.regular:
self.landscapeConstraint.isActive = false
self.portraitConstraint.isActive = true
default: // This shouldn't happen but let's assume regular (i.e. portrait)
self.landscapeConstraint.isActive = false
self.portraitConstraint.isActive = true
}
}
}
基本上你设置了固定的约束,即左、右和底部,然后设置纵向和横向的约束(常规和紧凑的垂直尺寸 class),这两个约束在默认情况下都是禁用的。 然后你根据当前orientation/sizeclass决定激活哪一个。 然后你覆盖:
willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)
基于新orientation/sizeclass.
的两个约束的方法和swap active state需要注意的一件事是始终先停用约束,然后再激活约束以避免任何抱怨无法满足的约束。