web-dev-qa-db-fra.com

safeAreaInsets dans UIView est 0 sur un iPhone X

Je suis en train de mettre à jour mon application pour l'adapter à iPhone X. Tous les affichages fonctionnent correctement, sauf un. J'ai un contrôleur de vue qui présente une UIView personnalisée qui couvre tout l'écran. Avant, j’utilisais UIScreen.main.bounds pour connaître la taille de la vue avant que toute la mise en page ne soit terminée (j’en ai besoin pour placer le bon itemSize dans une collectionView). Je pensais que je pouvais maintenant faire quelque chose comme UIScreen.main.bounds.size.height - safeAreaInsets.bottom pour obtenir la bonne taille utilisable. Le problème est que safeAreaInsets renvoie (0,0,0,0) une tentative sur un iPhone X (simulateur). Des idées? Dans d'autres vues, j'obtiens les bons numéros pour safeAreaInsets.

Je vous remercie!

52
Joan Cardona

Je trouvais déjà la solution: je faisais toute l'implémentation dans la init de la vue. safeAreaInsets a la taille correcte dans layoutSubviews()

37
Joan Cardona

J'ai récemment eu un problème similaire où les encarts de la zone sécurisée sont renvoyés (0, 0, 0, 0) dès que viewDidLoad est déclenché. Il semble qu'ils soient définis un peu plus tard que le reste du chargement de la vue.

Je l'ai contourné en surchargeant viewSafeAreaInsetsDidChange et en faisant ma mise en page de la manière suivante:

override func viewSafeAreaInsetsDidChange() {
 // ... your layout code here
} 
51

J'ai également rencontré ce problème en essayant de déplacer des vues vers le haut pour faire place au clavier de l'iPhone X. Les arrières safeAreaInsets de la vue principale sont toujours 0, même si je sais que les sous-vues ont été définies à cet endroit, à l'écran. a été dessiné. Un travail que j'ai trouvé, comme mentionné ci-dessus, consiste à récupérer la clé KeyWindow et à vérifier ses encarts de zone de sécurité.

Obj-C:

CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;

Rapide:

let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom

Vous pouvez ensuite utiliser cette valeur pour ajuster les contraintes ou afficher les cadres selon les besoins.

23
Rory Prior

J'ai une vue qui est une sous-vue dans une autre vue. J'ai constaté que je ne pouvais pas obtenir correctement safeAreaInsets, il retournait toujours 0, dans cette vue sur iPhoneX, même si je le mettais dans layoutSubviews. La solution finale est d’utiliser l’extension UIScreen suivante pour détecter les safeAreaInsets 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

        }

    }

}
18
Shih Ken

la méthode viewDidAppear (_ :) du contrôleur de vue conteneur qui étend la zone sécurisée de son contrôleur de vue enfant intégré pour prendre en compte les vues dans.

Apportez vos modifications dans cette méthode car les encarts de la zone sécurisée pour une vue ne sont pas précis tant que la vue n'est pas ajoutée à une hiérarchie de vues.

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
  } 
}
2
BuLB JoBs

J'ai rencontré le même problème. Dans mon cas, la vue que j'insère sera dimensionnée correctement après l'appel de view.layoutIfNeeded(). Le view.safeAreaInsets a été défini après cela, mais seule la valeur top était correcte. La valeur inférieure était toujours 0 (ceci sur un iPhone X).

Tout en essayant de déterminer à quel moment les safeAreaInsets sont correctement définis, j'ai ajouté un point d'arrêt à la méthode safeAreaInsetsDidChange() de la vue. Cela a été appelé plusieurs fois, mais seulement lorsque j'ai vu CALayer.layoutSublayers() dans la trace, la valeur avait été définie correctement.

J'ai donc remplacé view.layoutIfNeeded() par le correspondant de CALayerview.layer.layoutIfNeeded(), ce qui a permis de régler correctement le safeAreaInsets, résolvant ainsi mon problème.

TL; DR

Remplacer

view.layoutIfNeeded()

par

view.layer.layoutIfNeeded()
1
fphilipe
[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero
0
tounaobun

Essayez simplement self.view.safeAreaInsets au lieu de UIApplication.shared.keyWindow?.safeAreaInsets Les zones insérées ne semblent pas se remplir sur les appareils iOS 11.x.x à la demande via l'application keyWindow.

0
Murat Yasar