safeAreaInsets dans UIView est 0 sur un iPhone X
je suis en train de mettre à jour mon application pour l'adapter pour iPhone X. Toutes les vues fonctionnent bien maintenant sauf une. J'ai un contrôleur de vue qui présente un uivi personnalisé qui couvre l'écran entier. Avant j'utilisais UIScreen.main.bounds
pour connaître la taille de la vue avant que toute la mise en page ait été faite (j'en ai besoin pour mettre la bonne taille d'item pour une vue de collection). J'ai pensé que maintenant, je pouvais faire quelque chose comme
UIScreen.main.bounds.size.height - safeAreaInsets.bottom
pour obtenir la bonne taille utilisable. Le problème est que safeAreaInsets retourne (0,0,0, 0) en essayant sur un iPhone X (Simulateur.) Des idées? Dans d'autres vues, j'ai les bons numéros pour les coffres-forts.
Merci!
6 réponses
j'ai déjà trouvé la solution: je faisais toute l'implémentation dans le init
de la vue. safeAreaInsets a la taille correcte en layoutSubviews()
j'ai une vue qui est une sous-vue à l'intérieur d'une autre vue. J'ai trouvé que je ne peux pas obtenir safeAreaInsets correctement, il retourne toujours 0, dans cette vue sur iPhoneX, même si je l'ai mis dans layoutSubviews. La solution finale est que j'utilise la suite UIScreen extension pour détecter les appareils de sécurité qui peuvent fonctionner comme un charme.
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
}
}
}
j'ai eu récemment un problème similaire où les inserts de la zone de sécurité reviennent (0, 0, 0, 0) dès que le viewDidLoad est déclenché. Il semble qu'ils soient positionnés fractionnellement plus tard que le reste du chargement de la vue.
j'ai eu le tour, en remplaçant viewSafeAreaInsetsDidChange et en faisant ma mise en page qu'à la place:
override func viewSafeAreaInsetsDidChange() {
// ... your layout code here
}
j'ai moi aussi essayé de déplacer les vues pour faire place au clavier de l'iPhone X. les signaux de sécurité de la vue principale sont toujours 0, même si je sais que les sous-vues ont été disposées à ce point comme l'écran a été dessiné. Un travail autour que j'ai trouvé, comme et mentionné ci-dessus, est d'obtenir la fenêtre de la clé et de vérifier ses insets zone sûre à la place.
Obj-C:
CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
Swift:
let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom
Vous pouvez ensuite utiliser cette valeur pour ajuster les contraintes ou visionner les cadres selon les besoins.
j'ai rencontré le même problème. Dans mon cas, la vue que j'insère serait dimensionnée correctement après avoir appelé view.layoutIfNeeded()
. view.safeAreaInsets
a été fixé après cela, mais seulement le top
la valeur était correcte. La valeur inférieure était encore 0
(ceci sur un iPhone X).
Tout en essayant de comprendre à quel point l' safeAreaInsets
sont définies correctement, j'ai ajouté un point d'arrêt sur la vue safeAreaInsetsDidChange()
méthode. Ce qui a été appelé plusieurs fois, mais seulement quand j'ai vu CALayer.layoutSublayers()
dans le backtrace l' la valeur avait été définie correctement.
Donc j'ai remplacé view.layoutIfNeeded()
par CALayer
'homologue view.layer.layoutIfNeeded()
, qui a abouti à l' safeAreaInsets
pour être réglé correctement tout de suite, donc résoudre mon problème.
TL;DR
Remplacer
view.layoutIfNeeded()
par
view.layer.layoutIfNeeded()
la méthode viewDidAppear(_:) du contrôleur de vue de conteneur qui étend la zone de sécurité de son contrôleur de vue enfant intégré pour tenir compte des vues dans .
faites vos modifications dans cette méthode parce que les insets de zone de sécurité pour une vue ne sont pas précis tant que la vue n'est pas ajoutée à une hiérarchie de vue.
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
}
}