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!

20
demandé sur Joan Cardona 2017-10-31 13:16:43

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()

21
répondu Joan Cardona 2017-10-31 10:24:17

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

        }

    }

}
11
répondu Shih Ken 2017-12-16 03:01:17

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
} 
9
répondu Richard West-Soley 2018-05-18 20:05:36

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.

5
répondu Rory Prior 2018-05-18 11:29:07

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()
2
répondu fphilipe 2018-01-12 17:46:45

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
  } 
}
1
répondu BuLB JoBs 2017-10-31 10:30:31