77 votes

safeAreaInsets dans UIView est 0 sur un iPhone X

Je suis en train de mettre à jour mon application pour l'adapter à l'iPhone X. Toutes les vues fonctionnent bien maintenant, sauf une. 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 la mise en page ne soit terminée (j'en ai besoin pour déterminer la taille correcte des éléments d'une collectionView). Je pensais que maintenant je pourrais 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) en essayant sur un iPhone X (Simulateur). Avez-vous une idée ? Dans d'autres vues, j'obtiens les bons chiffres pour safeAreaInsets.

Merci !

4 votes

N'importe où, n'importe quand, vous pouvez utiliser : ` if #available(iOS 11.0, tvOS 11.0, *) { return UIApplication.shared.delegate ?.window ??.safeAreaInsets != .zero } return false` SOURCE

0 votes

Comme dans la réponse de Mars ci-dessous, je constate également que la seule façon fiable d'obtenir ces éléments est dans viewDidLayoutSubviews() ou viewDidAppear. En fait, "override func viewSafeAreaInsetsDidChange()" semble être la meilleure solution.

94voto

J'ai récemment eu un problème similaire où les inserts de la zone de sécurité retournent (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 de faire ma mise en page dans ce lieu :

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

1 votes

Idem - c'est correct - même si c'est un peu stupide que ce soit le cas.

2 votes

Si le PO souhaite effectuer cette opération dans la vue personnalisée plutôt que dans le contrôleur de vue, il existe également la méthode UIView. safeAreaInsetsDidChange .

1 votes

C'est parfait si vous configurez vos cellules dans un viewcontroller.

43voto

Joan Cardona Points 705

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

11 votes

Si vous utilisez view dans un UIViewController vous pouvez également le faire dans viewDidLayoutSubviews() et cela devrait fonctionner comme cela a été le cas pour moi.

2 votes

Soyez conscient que les sous-vues de viewWillLayoutSubviews ont une valeur de saveAreaInsets incorrecte.

0 votes

Vous pouvez également le faire dans UIViewController.viewDidLayoutSubviews.

39voto

Rory Prior Points 392

J'ai également rencontré ce problème en essayant de déplacer des vues pour faire de la place au clavier sur l'iPhone X. Les safeAreaInsets de la vue principale sont toujours à 0, même si je sais que les sous-vues ont été disposées à ce stade lorsque l'écran a été dessiné. Une solution que j'ai trouvée, comme mentionné ci-dessus, est d'obtenir la keyWindow et de vérifier ses insets de zone de sécurité à 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 les cadres de visualisation selon vos besoins.

0 votes

Il fonctionne en mode portrait. Le paysage n'a pas la vue sur le dessus.

0 votes

Seule cette solution a fonctionné pour moi. viewSafeAreaInsetsDidChange() n'est parfois pas appelé du tout.

21voto

Shih Ken Points 427

J'ai une vue qui est une sous-vue dans une autre vue. J'ai découvert que je ne peux pas obtenir safeAreaInsets correctement, il retourne toujours 0, dans cette vue sur iPhoneX même si je le mets dans layoutSubviews. La solution finale est d'utiliser l'extension UIScreen suivante pour détecter les safeAreaInsets, ce qui fonctionne à merveille.

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 votes

Bien que ce code puisse répondre à la question, le fait de fournir un contexte supplémentaire concernant la raison et/ou la manière dont ce code répond à la question améliore sa valeur à long terme.

0 votes

Merci pour votre suggestion. J'ai déjà modifié ma réponse.

1 votes

J'ai constaté que lors de l'ajout manuel de sous-vues (même si elles utilisent autolayout), dans certains cas, comme les contrôleurs de vues de tableaux, safeAreaInsets est toujours égal à zéro. L'utilisation de la fenêtre de la touche d'application renvoie les inserts corrects de la zone de sécurité. Bien vu.

2voto

BuLB JoBs Points 588

La méthode viewDidAppear(_ :) du contrôleur de vues du conteneur qui étend la zone de sécurité de son contrôleur de vues enfant intégré pour tenir compte des vues dans .

Effectuez vos modifications selon cette méthode car les inserts de zone de sécurité d'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
  } 
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X