Ответ 1
Я уже выяснил решение: я выполнял всю реализацию в init
представления. safeAreaInsets имеет правильный размер в layoutSubviews()
Я обновляю свое приложение, чтобы адаптировать его для iPhone X. Все представления работают отлично, кроме одного. У меня есть контроллер представления, который представляет пользовательский UIView, который охватывает весь экран. Прежде чем я использовал UIScreen.main.bounds
, чтобы узнать размер представления перед тем, как был выполнен весь макет (мне нужно его для размещения правильного itemSize для коллекцииView). Я думал, что теперь я могу сделать что-то вроде
UIScreen.main.bounds.size.height - safeAreaInsets.bottom
, чтобы получить правильный размер. Проблема в том, что safeAreaInsets возвращает (0,0,0,0), пробуя на iPhone X (Simulator). Есть идеи? В других представлениях я получаю правильные номера для safeAreaInsets.
Спасибо!
Я уже выяснил решение: я выполнял всю реализацию в init
представления. safeAreaInsets имеет правильный размер в layoutSubviews()
У меня недавно была аналогичная проблема, когда вставки безопасной области возвращаются (0, 0, 0, 0), как только запускается viewDidLoad. Похоже, что они устанавливаются дробно позже, чем остальная загрузка вида.
Я обошел его, переопределив viewSafeAreaInsetsDidChange и сделав вместо этого свой макет:
override func viewSafeAreaInsetsDidChange() {
// ... your layout code here
}
У меня есть представление, которое является подвью в другом представлении. Я обнаружил, что я не могу правильно получить safeAreaInsets, он всегда возвращает 0, в этом представлении на iPhoneX, даже если я поместил его в layoutSubviews. Конечным решением является использование следующего расширения UIScreen для обнаружения safeAreaInsets, которые могут работать как шарм.
extension UIScreen {
func widthOfSafeArea() -> CGFloat {
guard let rootView = UIApplication.shared.keyWindow else { return 0 }
if #available(iOS 11.0, *) {
let leftInset = rootView.safeAreaInsets.left
let rightInset = rootView.safeAreaInsets.right
return rootView.bounds.width - leftInset - rightInset
} else {
return rootView.bounds.width
}
}
func heightOfSafeArea() -> CGFloat {
guard let rootView = UIApplication.shared.keyWindow else { return 0 }
if #available(iOS 11.0, *) {
let topInset = rootView.safeAreaInsets.top
let bottomInset = rootView.safeAreaInsets.bottom
return rootView.bounds.height - topInset - bottomInset
} else {
return rootView.bounds.height
}
}
}
Я столкнулся с этой проблемой слишком, пытаясь переместиться вверх, чтобы освободить место для клавиатуры на iPhone X. В файле safeAreaInsets основного вида всегда есть 0, хотя я знаю, что на данный момент подъязыки были выложены в качестве экрана был составлен. Работа, которую я обнаружил, как и упоминалось выше, заключается в том, чтобы получить keyWindow и проверить его безопасные области вставки.
Obj-C:
CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
Swift:
let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom
Затем вы можете использовать это значение для настройки ограничений или кадров представления по мере необходимости.
метод viewDidAppear (_:) контроллера представления контейнера, который расширяет безопасную область встроенного контроллера дочернего представления для учета представлений.
Внесите свои изменения в этот метод, поскольку вставки безопасной области для представления не точны, пока представление не будет добавлено в иерархию представлений.
override func viewDidAppear(_ animated: Bool) {
if (@available(iOS 11, *)) {
var newSafeArea = view.safeAreaInsets
// Adjust the safe area to accommodate
// the width of the side view.
if let sideViewWidth = sideView?.bounds.size.width {
newSafeArea.right += sideViewWidth
}
// Adjust the safe area to accommodate
// the height of the bottom view.
if let bottomViewHeight = bottomView?.bounds.size.height {
newSafeArea.bottom += bottomViewHeight
}
// Adjust the safe area insets of the
// embedded child view controller.
let child = self.childViewControllers[0]
child.additionalSafeAreaInsets = newSafeArea
}
}
Я столкнулся с той же проблемой. В моем случае вид, который я вставляю, будет правильно задан после вызова view.layoutIfNeeded()
. После этого был установлен view.safeAreaInsets
, но только значение top
было правильным. Нижнее значение было 0
(это на iPhone X).
При попытке выяснить, в какой момент настройки safeAreaInsets
установлены правильно, я добавил точку останова в методе представления safeAreaInsetsDidChange()
. Это вызывалось несколько раз, но только когда я увидел CALayer.layoutSublayers()
в обратном направлении, значение было установлено правильно.
Итак, я заменил view.layoutIfNeeded()
на экземпляр CALayer
view.layer.layoutIfNeeded()
, что привело к правильной установке safeAreaInsets
, что позволило решить мою проблему.
TL; DR
Заменить
view.layoutIfNeeded()
по
view.layer.layoutIfNeeded()
одна возможность, вы можете использовать [UIApplication sharedApplication].keyWindow.safeAreaInsets to solove
[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero
Просто попробуйте self.view.safeAreaInsets
вместо UIApplication.shared.keyWindow?.safeAreaInsets
Кажется, что вставки безопасной области не заполняются на устройствах iOS 11.xx при запросе через keyWindow приложения.
У вас также есть опция, если вы используете автоматическую компоновку, чтобы придерживаться нижнего ограничения для просмотра. view.safeAreaLayoutGuide.bottomAnchor
! Ваш макет будет постоянно обновляться без необходимости наблюдать за изменениями.