web-dev-qa-db-fra.com

Problème lié à la barre d'état pendant l'appel UIViewController

Problème:

Le contrôleur de vue présenté de façon modale ne remonte pas après la disparition de la barre d'état en cours d'appel, laissant un espace vide/transparent de 20 pixels en haut.


Normal: Aucun problème

 enter image description here


En appel: aucun problème

 enter image description here


Après la disparition de l'appel en cours:

Laisse un espace vide/transparent de 20 pixels de haut en haut, laissant apparaître la vue orange ci-dessous. Cependant, la barre d'état est toujours présente sur la zone transparente. La barre de navigation laisse également de la place pour la barre d’état, son placement n’est que de 20 pixels.

 enter image description here

 enter image description here


  • basé sur iOS 10 
  • Contrôleur de vue présenté de manière modale 
  • Présentation modale personnalisée
  • Le contrôleur de vue principale derrière est orange
  • Ne pas utiliser Autolayout
  • Lorsqu’elle est tournée vers Paysage, la barre d’appel en appel de 20 pixels quitte et laisse toujours un espace vide de 20 pixels.
  • Je désactive l'affichage de la barre d'état dans les orientations de paysage. (ie la plupart des applications stock)

J'ai essayé d'écouter les délégués de l'application:

willChangeStatusBarFrame
didChangeStatusBarFrame

Afficher également les notifications basées sur le contrôleur:

UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame

Lorsque je consigne le cadre de la vue présentée pour les quatre méthodes ci-dessus, le cadre est toujours à (y: 0) Origine.


Mettre à jour

View Controller Présentation modale personnalisée

    let storyboard = UIStoryboard(name: "StoryBoard1", bundle: nil)
    self.modalVC = storyboard.instantiateViewController(withIdentifier: "My Modal View Controller") as? MyModalViewController
    self.modalVC!.transitioningDelegate = self
    self.modalVC.modalPresentationStyle = .custom
    self.modalVC.modalPresentationCapturesStatusBarAppearance = true;
    self.present(self.modalVC!, animated: true, completion: nil)


    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        toViewController!.view.transform = CGAffineTransform(scaleX: 0.001, y: 0.001)

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0, options: [.curveEaseOut], animations: { () -> Void in

            toViewController!.view.transform = CGAffineTransform.identity

        }, completion: { (completed) -> Void in

           transitionContext.completeTransition(completed)

        })
 }
17
Gizmodo

J'ai fait face à ce problème aussi mais après avoir mis cette méthode, le problème est parti.

iOS a sa méthode par défaut willChangeStatusBarFrame pour gérer la barre d'état. S'il vous plaît mettez cette méthode et vérifiez-la. 

func application(_ application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect) {
    UIView.animate(withDuration: 0.35, animations: {() -> Void in
        let windowFrame: CGRect? = ((window?.rootViewController? as? UITabBarController)?.viewControllers[0] as? UINavigationController)?.view?.frame
        if newStatusBarFrame.size.height > 20 {
            windowFrame?.origin?.y = newStatusBarFrame.size.height - 20
            // old status bar frame is 20
        }
        else {
            windowFrame?.origin?.y = 0.0
        }
        ((window?.rootViewController? as? UITabBarController)?.viewControllers[0] as? UINavigationController)?.view?.frame = windowFrame
    })
}

J'espère que cette chose va vous aider.
Je vous remercie

4
Jitendra Modi

Je cherche une solution depuis 3 jours. Je n'aime pas cette solution mais je n'ai pas trouvé de meilleur moyen de la réparer.

Il y a une situation où la vue rootViewController a une hauteur supérieure de 20 points à celle de la fenêtre. Lorsque j'ai une notification concernant les mises à jour de la hauteur de la barre d'état, je configure manuellement la valeur correcte.

Ajouter une méthode à la AppDelegate.Swift

func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
        if let window = application.keyWindow {
            window.rootViewController?.view.frame = window.frame
        }
    }

Après cela, cela fonctionne comme prévu (même après les changements d’orientation) ... Je pense que ça va aider quelqu'un, parce que j’ai passé trop de temps là-dessus.

P.S. Il clignote un peu, mais fonctionne.

4
Bws Sluk

Je pense que c'est un bug dans UIKit. La containerView qui contient la vue d'un contrôleur présenté qui a été présentée à l'aide d'une transition personnalisée ne semble pas revenir complètement lorsque la barre d'état a retrouvé sa taille normale. (Vous pouvez vérifier la hiérarchie des vues après avoir fermé la barre d'état de l'appel)

Pour le résoudre, vous pouvez fournir un contrôleur de présentation personnalisé lors de la présentation. Et puis, si vous n'avez pas besoin que la vue du contrôleur présentateur reste dans la hiérarchie des vues, vous pouvez simplement renvoyer la propriété true pour shouldRemovePresentersView du contrôleur de présentation, et c'est tout.

func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    return PresentationController(presentedViewController: presented, presenting: presenting)
}

class PresentationController: UIPresentationController {
    override var shouldRemovePresentersView: Bool {
        return true
    }
}

ou si vous souhaitez que la vue du contrôleur présentateur soit conservée, vous pouvez observer le changement de cadre de la barre d'état et ajuster manuellement la variable containerView pour qu'elle ait la même taille que sa vue d'ensemble.

class PresentationController: UIPresentationController {
    override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.onStatusBarChanged),
                                               name: .UIApplicationWillChangeStatusBarFrame,
                                               object: nil)
    }

    @objc func onStatusBarChanged(note: NSNotification) {
        //I can't find a way to ask the system for the values of these constants, maybe you can
        if UIApplication.shared.statusBarFrame.height <= 20,
            let superView = containerView?.superview {
            UIView.animate(withDuration: 0.4, animations: {
                self.containerView?.frame = superView.bounds
            })
        }
    }
}
3
riadhluke

J'ai eu le même problème avec l'hospot personnel qui modifiait la barre d'état .. La solution consiste à s'inscrire à la notification système pour le changement de cadre de la barre d'état, cela vous permettra de mettre à jour votre mise en page et de corriger tout problème de mise en page que vous pourriez rencontrer as . Ma solution qui devrait fonctionner exactement de la même manière pour vous est la suivante:

  • Dans votre contrôleur de vue, dans viewWillAppear, abonnez-vous à la UIApplicationDidChangeStatusBarFrameNotification

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(myControllerName.handleFrameResize(_:)), name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • Créez votre méthode de sélection 

    func handleFrameResize(notification: NSNotification) {
    self.view.layoutIfNeeded() }
    
  • Supprimez votre contrôleur du centre de notification dans viewWillDisappear

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • Vous avez également besoin que votre modal soit en charge de la barre d'état, vous devez donc définir 

    destVC.modalPresentationCapturesStatusBarAppearance = true avant de présenter la vue.

Vous pouvez soit implémenter cela sur chaque contrôleur susceptible de modifier la barre d'état, soit créer une autre classe qui le fera pour chaque contrôleur, par exemple, passer à une méthode, conserver la référence pour modifier la présentation et disposer d'une méthode. se retirer. Vous savez, afin de réutiliser le code.

3
thibaut noah

Je cherchais une solution à ce problème. En fait, j'ai posté une nouvelle question semblable à celle-ci. Ici: Comment éviter la barre de navigation d'emplacement bleu iOS Messing Up My StatusBar?

Croyez-moi, je résous ce problème depuis quelques jours maintenant et il est vraiment agaçant de perdre votre écran en raison des modifications apportées à la barre d'état d'iOS par appel entrant, point d'accès sans fil et emplacement.

J'ai essayé d'implémenter la réponse de Modi, j'ai mis ce morceau de code dans mon AppDelegate et l'ai légèrement modifié, mais pas de chance. et je crois que iOS le fait automatiquement afin que vous n'ayez pas à l'implémenter vous-même.

Avant de découvrir le coupable du problème, j'ai essayé toutes les solutions à cette question particulière. Pas besoin d'implémenter la méthode Appcode Code willChangeStatusBar... ou d'ajouter une notification pour observer les changements de statusBar.

J'ai également refait certains des flux de mon projet, en effectuant des écrans par programmation (j'utilise des story-boards). Et j’ai expérimenté un peu, puis j’ai inspecté mes précédents et d’autres projets en cours pour savoir pourquoi ils faisaient les ajustements correctement :)

Bottom line is: Je présente mon écran principal avec UITabBarController de manière si erronée.

Veuillez toujours prendre note de la modalPresentationStyle. J'ai eu l'idée de vérifier mon code à cause du commentaire de Noah. 

Échantillon:

func presentDashboard() {
    if let tabBarController = R.storyboard.root.baseTabBarController() {
        tabBarController.selectedIndex = 1
        tabBarController.modalPresentationStyle = .fullScreen
        tabBarController.modalTransitionStyle = .crossDissolve

        self.baseTabBarController = tabBarController
        self.navigationController?.present(tabBarController, animated: true, completion: nil)
    }
}
3
Glenn

Je résous ce problème en utilisant une ligne de code

En Objectif C

tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);

En rapide

self.tabBarController?.tabBar.autoresizingMask = 
  UIViewAutoresizing(rawValue: UIViewAutoresizing.RawValue(UInt8(UIViewAutoresizing.flexibleWidth.rawValue) | UInt8(UIViewAutoresizing.flexibleTopMargin.rawValue)))`

Il vous suffit de rendre autoresizingMask de tabBar flexible en partant du haut.

1
Sahil_Saini

Veillez à définir le cadre de la vue du contrôleur de vue que vous présentez sur les limites de la vue du conteneur, après l'avoir ajouté à la vue du conteneur. Cela a résolu le problème pour moi.

containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds
0
Colin R