2 votes

topLayoutGuide appliqué après viewWillAppear

J'ai le problème que le topLayoutGuide.length dans un UIViewController (de XIB) est fixé après viewWillAppear et je ne sais pas comment me brancher sur le changement de topLayoutGuide.length pour définir initialement le ContentOffset d'une vue de tableau.

Code pour présenter de façon modale un UIViewController à l'intérieur d'un UINavigationController :

let viewController = UIViewController(nibName: "ViewController", bundle: nil)
let navigationController = UINavigationController(rootViewController: viewController)
present(navigationController, animated: true, completion: nil)

Ma sortie de débogage concernant le topLayoutGuide.length

Init view controller
-[UIViewController topLayoutGuide]: guide not available before the view controller's view is loaded
willMove toParentViewController  - top layout guide nan
Init navigation controller and pass view controller as root vc
Present navigation controller modally
viewDidLoad                      - top layout guide 0.0
viewWillAppear                   - top layout guide 0.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0
viewDidAppear                    - top layout guide 64.0
didMove toParentViewController   - top layout guide 64.0
viewWillLayoutSubviews           - top layout guide 64.0
viewDidLayoutSubviews            - top layout guide 64.0

Pour l'instant, j'utilise un drapeau bool dans le contrôleur de vue pour définir le décalage de contenu dans le fichier de configuration. viewDidLayoutSubviews une seule fois, même si la méthode est appelée plusieurs fois.

Avez-vous une solution plus élégante en tête ?

3voto

Mischa Points 1005

Le site la documentation pour le topLayoutGuide déclare explicitement :

Interrogez cette propriété dans votre implémentation de l viewDidLayoutSubviews() méthode.

A en juger par vos propres inspections, le point le plus précoce pour obtenir la topLayoutGuide La longueur réelle de l'article se trouve à l'intérieur de la viewWillLayoutSubviews() méthode. Toutefois, je ne m'y fierais pas et je le ferais en viewDidLayoutSubviews() comme le suggère la documentation.

La raison pour laquelle vous ne pouvez pas accéder à la propriété plus tôt...

... est que les guides de mise en page sont des objets qui dépendent de la mise en page de tout contrôleur de vue conteneur. Les vues sont disposées paresseusement lorsqu'elles sont nécessaires à l'écran. Ainsi, lorsque vous ajoutez le viewController à la navigationViewController comme son contrôleur de vue racine il n'est pas encore mis en place.

La mise en page se produit lorsque vous présentez le navigationController . À ce moment-là, les vues des deux contrôleurs de vue sont chargées (→ viewDidLoad() , viewWillAppear() ), puis une passe de mise en page est déclenchée. Tout d'abord, le navigationViewController La vue de l'utilisateur est mise en page (flux de mise en page : superview → subview). Le cadre de la barre de navigation est réglé sur une hauteur de 64 px. Maintenant, la viewController 's topLayoutGuide peuvent être définis. Et enfin, le viewController Le point de vue de l'entreprise est exposé (→ viewWillLayoutSubviews() , viewDidLayoutSubviews() ).

Conclusion :

La seule façon de faire initial Les ajustements de mise en page qui dépendent de la longueur du guide de mise en page est la méthode que vous avez suggérée vous-même :

  1. Ayez une propriété booléenne dans votre contrôleur de vue que vous définissez à true initialement :

    var isInitialLayoutPass: Bool = true 
  2. À l'intérieur de viewDidLayoutSubviews() vérifier cette propriété et n'effectuer votre mise en page initiale que lorsqu'elle est true :

    func viewDidLayoutSubviews() {
        if isInitialLayoutPass {
            tableView.contentOffset = CGPoint(x: 0, y: topLayoutGuide.length)
        }
    }
  3. À l'intérieur de viewDidAppear() la propriété est fixée à false pour indiquer que la mise en page initiale est terminée :

    override func viewDidAppear() {
        super.viewDidAppear()
        isInitialLayoutPass = false
    }

Je sais que c'est un peu compliqué, mais j'ai bien peur que ce soit la seule façon de procéder (à laquelle je pense), à moins que vous ne vouliez utiliser observation des valeurs clés (KVO) ce qui ne rend pas les choses beaucoup plus claires à mon avis.

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