safeAreaInsets в UIView-0 на iPhone X
Я обновляю свое приложение, чтобы адаптировать его для iPhone X. Все представления теперь работают нормально, кроме одного. У меня есть контроллер вида, который представляет пользовательский UIView, который охватывает весь экран. Прежде чем я использовал UIScreen.main.bounds
чтобы узнать размер представления до того, как был сделан весь макет (он нужен мне для размещения правильного itemSize для collectionView). Я думал, что теперь смогу сделать что-то вроде
UIScreen.main.bounds.size.height - safeAreaInsets.bottom
чтобы получить правильный полезный размер. Проблема в том, что safeAreaInsets возвращает (0,0,0,0), пытаясь на iPhone X (Тренажер.) Есть идеи? В других представлениях я получаю правильные номера для safeAreaInsets.
спасибо!
6 ответов
Я уже придумал решение: я делал всю реализацию в init
представления. safeAreaInsets имеет правильный размер в layoutSubviews()
У меня есть представление, которое является подвидом внутри другого представления. Я обнаружил, что не могу получить 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
}
}
}
недавно у меня была аналогичная проблема, когда вставки безопасной области возвращаются (0, 0, 0, 0), как только запускается viewDidLoad. Кажется, что они установлены немного позже, чем остальная часть загрузки представления.
Я обошел его, переопределив viewSafeAreaInsetsDidChange и делать мой макет вместо этого:
override func viewSafeAreaInsetsDidChange() {
// ... your layout code here
}
я столкнулся с этой проблемой, пытаясь переместить представления, чтобы освободить место для клавиатуры на iPhone X. safeAreaInsets основного представления всегда равны 0, хотя я знаю, что подвиды были выложены в этот момент, когда экран был нарисован. Работа вокруг я нашел, как и упоминалось выше, чтобы получить keyWindow и проверить его безопасные области вставки вместо этого.
Obj-C:
CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
Свифт:
let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom
затем вы можете использовать это значение для регулировки ограничения или рамки вида по мере необходимости.
я столкнулся с той же проблемой. В моем случае представление, которое я вставляю, будет правильно определено после вызова view.layoutIfNeeded()
. The view.safeAreaInsets
был установлен после этого, но только top
значение было правильным. Нижнее значение по-прежнему 0
(это на iPhone X).
при попытке выяснить, в какой момент safeAreaInsets
установлены правильно, я добавил точку останова в представлении safeAreaInsetsDidChange()
метод. Это было несколько раз, но только когда я увидел CALayer.layoutSublayers()
в backtrace значение было установлено правильно.
Итак, Я заменил view.layoutIfNeeded()
на CALayer
с контрагентом view.layer.layoutIfNeeded()
, что привело к safeAreaInsets
чтобы быть установлен правильно сразу, тем самым решая мою проблему.
TL; DR
заменить
view.layoutIfNeeded()
by
view.layer.layoutIfNeeded()
метод 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
}
}