Использовать макет безопасной зоны программно
Поскольку я не использую раскадровки для создания своих представлений, мне было интересно, есть ли опция "Использовать безопасные области" программно или что-то в этом роде.
Я пытался закрепить свои взгляды на
view.safeAreaLayoutGuide
но они продолжают перекрывать высший уровень в симуляторе iPhone X.
12 ответов
Вот пример кода (ссылка: Руководство по разметке безопасной зоны):
Если вы создаете свои ограничения в коде, используйте свойство safeAreaLayoutGuide UIView, чтобы получить соответствующие привязки макета. Давайте воссоздаем приведенный выше пример Interface Builder в коде, чтобы посмотреть, как он выглядит:
Предполагая, что у нас есть зеленый вид как свойство в нашем контроллере вида:
private let greenView = UIView()
У нас может быть функция для установки представлений и ограничений, вызываемых из viewDidLoad:
private func setupView() {
greenView.translatesAutoresizingMaskIntoConstraints = false
greenView.backgroundColor = .green
view.addSubview(greenView)
}
Создайте ограничения начального и конечного полей, как всегда, используя layoutMarginsGuide корневого представления:
let margins = view.layoutMarginsGuide
NSLayoutConstraint.activate([
greenView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
greenView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
])
Теперь, если вы не нацелены только на iOS 11, вам нужно будет обернуть ограничения по макету безопасной области с помощью #available и вернуться к верхним и нижним руководствам по макету для более ранних версий iOS:
if #available(iOS 11, *) {
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
greenView.topAnchor.constraintEqualToSystemSpacingBelow(guide.topAnchor, multiplier: 1.0),
guide.bottomAnchor.constraintEqualToSystemSpacingBelow(greenView.bottomAnchor, multiplier: 1.0)
])
} else {
let standardSpacing: CGFloat = 8.0
NSLayoutConstraint.activate([
greenView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: standardSpacing),
bottomLayoutGuide.topAnchor.constraint(equalTo: greenView.bottomAnchor, constant: standardSpacing)
])
}
Результат:
Вот официальная документация Apple Developer для руководства по безопасной зоне
Безопасная зона необходима для обработки дизайна пользовательского интерфейса для iPhone-X. Вот базовое руководство по разработке пользовательского интерфейса для iPhone-X с использованием макета безопасной области
Я фактически использую расширение для этого и управляю, является ли это ios 11 или нет.
extension UIView {
var safeTopAnchor: NSLayoutYAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.topAnchor
} else {
return self.topAnchor
}
}
var safeLeftAnchor: NSLayoutXAxisAnchor {
if #available(iOS 11.0, *){
return self.safeAreaLayoutGuide.leftAnchor
}else {
return self.leftAnchor
}
}
var safeRightAnchor: NSLayoutXAxisAnchor {
if #available(iOS 11.0, *){
return self.safeAreaLayoutGuide.rightAnchor
}else {
return self.rightAnchor
}
}
var safeBottomAnchor: NSLayoutYAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.bottomAnchor
} else {
return self.bottomAnchor
}
}
}
SafeAreaLayoutGuide
является UIView
имущество,
Верхняя часть safeAreaLayoutGuide указывает на незатененный верхний край представления (например, не за строкой состояния или панелью навигации, если имеется). Аналогично для других краев.
использование safeAreaLayoutGuide
чтобы избежать обрезания / перекрытия наших объектов из закругленных углов, панелей навигации, панелей вкладок, панелей инструментов и других предков.
Мы можем создать safeAreaLayoutGuide
Объект и установить ограничения объекта соответственно.
Ограничения для Портрета + Пейзаж это -
self.edgesForExtendedLayout = []//Optional our as per your view ladder
let newView = UIView()
newView.backgroundColor = .red
self.view.addSubview(newView)
newView.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
let guide = self.view.safeAreaLayoutGuide
newView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
newView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
newView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
else {
NSLayoutConstraint(item: newView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: newView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: newView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true
newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
Для тех из вас, кто использует SnapKit, как и я, решение заключается в том, чтобы привязать ваши ограничения к view.safeAreaLayoutGuide
вот так:
yourView.snp.makeConstraints { (make) in
if #available(iOS 11.0, *) {
//Bottom guide
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottomMargin)
//Top guide
make.top.equalTo(view.safeAreaLayoutGuide.snp.topMargin)
//Leading guide
make.leading.equalTo(view.safeAreaLayoutGuide.snp.leadingMargin)
//Trailing guide
make.trailing.equalTo(view.safeAreaLayoutGuide.snp.trailingMargin)
} else {
make.edges.equalToSuperview()
}
}
Я использую это вместо того, чтобы добавлять начальные и конечные ограничения полей в layoutMarginsGuide:
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
yourView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[safe.trailingAnchor constraintEqualToAnchor:yourView.trailingAnchor],
[yourView.leadingAnchor constraintEqualToAnchor:safe.leadingAnchor],
[yourView.topAnchor constraintEqualToAnchor:safe.topAnchor],
[safe.bottomAnchor constraintEqualToAnchor:yourView.bottomAnchor]
]];
Пожалуйста, также проверьте опцию для более низкой версии IOS 11 из ответа Крунала.
Swift 4.2 и 5.0. Предположим, вы хотите добавить ограничения Leading, Trailing, Top и Bottom для viewBg. Итак, вы можете использовать приведенный ниже код.
let guide = self.view.safeAreaLayoutGuide
viewBg.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
viewBg.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
viewBg.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
viewBg.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
Использование UIWindow
или же UIView
"s safeAreaInsets
.bottom
.top
.left
.right
// #available(iOS 11.0, *)
// height - UIApplication.shared.keyWindow!.safeAreaInsets.bottom
// On iPhoneX
// UIApplication.shared.keyWindow!.safeAreaInsets.top = 44
// UIApplication.shared.keyWindow!.safeAreaInsets.bottom = 34
// Other devices
// UIApplication.shared.keyWindow!.safeAreaInsets.top = 0
// UIApplication.shared.keyWindow!.safeAreaInsets.bottom = 0
// example
let window = UIApplication.shared.keyWindow!
let viewWidth = window.frame.size.width
let viewHeight = window.frame.size.height - window.safeAreaInsets.bottom
let viewFrame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
let aView = UIView(frame: viewFrame)
aView.backgroundColor = .red
view.addSubview(aView)
aView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Безопасное расширение зоны для Objective-C
@implementation UIView (SafeArea)
- (NSLayoutAnchor *)safeTopAnchor{
if (@available(iOS 11.0, *)){
return self.safeAreaLayoutGuide.topAnchor;
} else {
return self.topAnchor;
}
}
- (NSLayoutAnchor *)safeBottomAnchor{
if (@available(iOS 11.0, *)) {
return self.safeAreaLayoutGuide.bottomAnchor;
} else {
return self.bottomAnchor;
}
}
@end
Используйте ограничения в визуальном формате, и вы получите уважение к безопасной зоне бесплатно.
class ViewController: UIViewController {
var greenView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
greenView.backgroundColor = .green
view.addSubview(greenView)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
greenView.translatesAutoresizingMaskIntoConstraints = false
let views : [String:Any] = ["greenView":greenView]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[greenView]-|", options: [], metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[greenView]-|", options: [], metrics: nil, views: views))
}
}
Это расширение помогает вам ограничить UIVIew его супервизором и супервизором +safeArea:
extension UIView {
///Constraints a view to its superview
func constraintToSuperView() {
guard let superview = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
topAnchor.constraint(equalTo: superview.topAnchor).isActive = true
leftAnchor.constraint(equalTo: superview.leftAnchor).isActive = true
bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
rightAnchor.constraint(equalTo: superview.rightAnchor).isActive = true
}
///Constraints a view to its superview safe area
func constraintToSafeArea() {
guard let superview = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
leftAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leftAnchor).isActive = true
bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true
rightAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.rightAnchor).isActive = true
}
}
Вы можете использовать view.safeAreaInsets, как описано здесь https://www.raywenderlich.com/174078/auto-layout-visual-format-language-tutorial-2
Пример кода (взят с сайта raywenderlich.com):
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
if !allConstraints.isEmpty {
NSLayoutConstraint.deactivate(allConstraints)
allConstraints.removeAll()
}
let newInsets = view.safeAreaInsets
let leftMargin = newInsets.left > 0 ? newInsets.left : Metrics.padding
let rightMargin = newInsets.right > 0 ? newInsets.right : Metrics.padding
let topMargin = newInsets.top > 0 ? newInsets.top : Metrics.padding
let bottomMargin = newInsets.bottom > 0 ? newInsets.bottom : Metrics.padding
let metrics = [
"horizontalPadding": Metrics.padding,
"iconImageViewWidth": Metrics.iconImageViewWidth,
"topMargin": topMargin,
"bottomMargin": bottomMargin,
"leftMargin": leftMargin,
"rightMargin": rightMargin]
}
let views: [String: Any] = [
"iconImageView": iconImageView,
"appNameLabel": appNameLabel,
"skipButton": skipButton,
"appImageView": appImageView,
"welcomeLabel": welcomeLabel,
"summaryLabel": summaryLabel,
"pageControl": pageControl]
let iconVerticalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "V:|-topMargin-[iconImageView(30)]",
metrics: metrics,
views: views)
allConstraints += iconVerticalConstraints
let topRowHorizontalFormat = """
H:|-leftMargin-[iconImageView(iconImageViewWidth)]-[appNameLabel]-[skipButton]-rightMargin-|
"""
...
var someVeiw = UIView()
func webView(_view: View, didFinish navigation: WKNavigation!) {
self.someVeiw.frame = view.safeAreaLayoutGuide.layoutFrame
}
iOS 10+ поставляется с safeAreaLayoutGuide, который обнаруживается во время выполнения.Frame on принимает CGRect , поэтому используйте layoutFrame