Включает ли руководство по планированию в безопасных зонах, совместимое с iOS ниже 11?
IOS 11 безопасная область
Ответ 1
Мне удалось работать с новыми руководствами по макету Safe Area и поддерживать обратную совместимость с iOS 9 и iOS 10: (EDIT: как указано в комментариях @NickEntin, эта реализация предполагает, что присутствует панель состояния, что не будет истинным в ландшафте iPhone X. В результате на много места на вершину (20 точки), но будет работать отлично.
например. если вы хотите, чтобы представление было на 10 пунктов ниже строки состояния (и на 10 пунктов ниже корпуса датчика на iPhone X):
- В вашем XIB перейдите к
File Inspector
и включите сейф, проверивUse Safe Area Layout Guides
. - Создайте ограничение сверху сверху на верхнюю часть верхнего представления с ограничением
>=
(больше или равным), константой30
(30, потому что мы хотим, чтобы 10-точечное расстояние до строки состояния было на 20 пунктов выше) и приоритетHigh
(750). - Создайте ограничение сверху сверху на верхнюю часть Safe Area, с
=
(равным) ограничением, константой10
и приоритетомLow
(250).
То же самое можно сделать для представления внизу (и для ведущего/конечного или левого/правого для безопасной области):
- В вашем XIB перейдите к
File Inspector
и включите сейф, проверивUse Safe Area Layout Guides
. - Создайте ограничение с нижней части представления на нижнюю часть представления, с ограничением
>=
(больше или равно), константой10
и приоритетомHigh
(750). - Создайте ограничение со дна представления в нижней части Безопасной зоны, с
=
(равным) ограничением, константой10
и приоритетомLow
(250).
Ответ 2
Обратная совместимость Safe Areas для iOS 9 & iOS 10 работает, только если вы используете раскадровки. Если вы используете xibs, нет руководства по компоновке, к которому можно обратиться. https://forums.developer.apple.com/thread/87329
Обходные пути кажутся либо
(a) перенесите свои xibs в раскадровки или
(б) добавить некоторые дополнительные ограничения программно.
Если (а) на самом деле не вариант, ручной подход будет выглядеть примерно так:
Предполагая, что в вашей 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
}
}
}
Ответ 3
Есть определенно, по крайней мере, одна проблема с обратной совместимостью с ограничениями безопасной зоны iOS 11, которые я наблюдал в контроллерах Xcode 9 GM с токовыми контрольными точками.
Если ваша панель навигации скрыта, и вы нажмете верхнее ограничение безопасности, то сдвинутое представление будет перекрывать строку состояния на iOS 9 и 10.
Если панель навигации видна, а "под верхними барами" отключено, то нажатый вид будет показываться под навигационной панелью, чтобы попасть в верхнюю часть экрана. Панель навигации размещена правильно.
В iOS 11 макет будет правильным в обоих случаях.
Вот простой пример: http://www.filedropper.com/foobar
И вот видео с ним w/nav bar скрыто (iOS 10.3 слева, iOS 11 справа): https://vimeo.com/234174841/1e27a96a87 p >
Здесь версия, в которой отображается панель навигации (включена в бандере): https://vimeo.com/234316256/f022132d57
Я подал это как радар # 34477706.
Благодаря @Sander, чтобы указать видимый случай навигационной панели.
Ответ 4
Да, ваш проект/приложение будет работать в версиях iOS до iOS 11 без каких-либо проблем. В версиях iOS до 11 он заменяет/рассматривает конфигурацию безопасной области в обычном AutoLayout и соответствует правилам руководства по началу и нижней части правил.
Я протестировал свой существующий проект с помощью и без "SafeAreaLayout" на обеих платформах (iOS 11 и обратный iOS 10). Он отлично работает.
Просто убедитесь, что:
Если вы разработали свой проект/пользовательский интерфейс в AutoLayout; ограничения вашего UIElement следуют за/сверху и снизу руководство по макету (не для просмотра). Таким образом, одним нажатием кнопки (включить) Опция SafeAreaLayout будет автоматически реализовывать макет SafeArea правильно для всех файлов Interface Builders в вашем раскадровке.
Если вы разработали свой проект/пользовательский интерфейс в SafeAreaLayout; то он автоматически будет следовать руководству макета Top и Bottom в назад iOS.
Вот пример моментального снимка с результатом. Включение или отключение макета Safe Area не повлияет на существующий дизайн.
AutoLayout
Короче говоря, ответ на ваш вопрос: "Включение руководств по планированию безопасных областей, совместимых с iOS до 11",
В вашем проекте/приложении вы можете реализовать форму безопасного расположения, и она будет отлично работать с предыдущими версиями iOS преобразование формы безопасной области в верхний и нижний макет.
Ответ 5
Если вы используете xibs без раскадровки, тогда у них нет руководств по расположению на ios 10. Поэтому переместите xib в раскадровку, чтобы иметь обратную совместимость.
Ответ 6
Я использовал это в Objective-C с хорошим результатом для iOS 10.
Если вы используете SafeArea в xib, вы можете добавить в viewDidLoad
:
if (@available(iOS 11.0, *)) {}
else {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
Ответ 7
"Руководство по планированию безопасной зоны" совместимо с обратной связью. Ну, если вы не используете его в xib. С раскадрой кажется, что это нормально.
Я решил свою проблему, обратившись к "Верхнему ограничению макета" из первого объекта в верхней части моего представления.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;
то я изменил значение Constant на это ограничение и обновил представление. Например, если вы используете навигационную панель (высота 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)
Ответ 8
Я нашел более удобный способ, когда вам нужно всего лишь создать подкласс NSLayoutConstraint
, который прикреплен к вашему safeArea
.
Это немного странно, поскольку вы должны получить ViewController из UIView, но, на мой взгляд, это простая и хорошая альтернатива, пока Apple окончательно не исправит обратную совместимость для safeArea в 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:
Ответ 9
У меня проблемы с обратной совместимостью с WKWebView и Safe Area на iOS 9. По какой-то причине WKWebView просто игнорирует безопасные настройки макета области.
Ответ 10
В Objective-C для верхнего и нижнего полей, когда на iPhone-X
if (@available(iOS 11, *)) {
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.childView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.parentView.safeAreaLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.childView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.parentView.safeAreaLayoutGuide
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
} else {
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.childView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.parentView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.childView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.parentView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
}
Ответ 11
Вот что я сделал с моими проектами
В моем случае оба моих topConstraint
и bottomConstraint
являются @IBOutlet
s. Это также совместимо с iOS 8
.
Моя первоначальная конфигурация для верхнего и нижнего ограничений предназначена для обычных iPhone, поэтому я редактирую ограничения только для iPhone X
// iOS 11 Layout Fix. (For iPhone X)
if #available(iOS 11, *) {
self.topConstraint.constant = self.topConstraint.constant + self.view.safeAreaInsets.top
self.bottomConstraint.constant = self.bottomConstraint.constant + self.view.safeAreaInsets.bottom
}
.
ПРИМЕЧАНИЕ: self.view
- это ваш superView, поэтому я использую его для safeAreaInsets
Ответ 12
Если у вас есть универсальный ViewController, который расширяют все ваши ViewController, другим решением будет поместить элементы, которые должны быть отрегулированы, в IBOutletCollection и программно настроить их в этом GenericViewController. Вот мой код:
@IBOutlet var adjustTopSpaceViews: [UIView]?
override func viewDidLoad() {
super.viewDidLoad()
adjustViews()
....
}
func adjustViews() {
guard let views = adjustTopSpaceViews,
ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11 else {
return
}
let statusBarHeight = UIApplication.shared.statusBarFrame.height
for subview in views {
subview.superview?.constraints.filter({ (constraint) -> Bool in
return constraint.firstAttribute == .top
&& constraint.secondAttribute == .top
&& (constraint.firstItem as? UIView == subview || constraint.secondItem as? UIView == subview)
}).forEach({ (constraint) in
constraint.constant += (constraint.firstItem as? UIView == subview) ? statusBarHeight : -statusBarHeight
})
}
}
Ответ 13
Вот моя оболочка решения от iOS 9 до iOS 11+ в быстром 4+
let safeAreaTopAnchor:NSLayoutYAxisAnchor?
if #available(iOS 11.0, *) {
safeAreaTopAnchor = contentView.safeAreaLayoutGuide.topAnchor
} else {
// Fallback on earlier versions
var parentViewController: UIViewController? {
var parentVCResponder: UIResponder? = self
while parentVCResponder != nil {
parentVCResponder = parentVCResponder!.next
if let viewController = parentVCResponder as? UIViewController {
return viewController
}
}
return nil
}
safeAreaTopAnchor = parentViewController?.topLayoutGuide.bottomAnchor
}
Ответ 14
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)