Comportement du Layout Engine

ifouifou Membre

Bonjour à  toutes et tous,


 


 


Je découvre UIKit ces derniers temps. Et en faisant divers tests, des questions (qui doivent vous être bien basique) me viennent à  l'esprit. J'aimerais vous les soumettre car j'essaie de comprendre ce qu'il se passe.


 


Aujourd'hui cela concerne le "Layout Engine" dont je ne comprends pas un des comportements. En effet il semblerait qu'il bouge un des mes buttons alors qu'aucune contraintes ne lui ai appliqué.


 


Note pour la suite: dans le code qui suit j'ai bien désactivé la propriété "translatesAutoresizingMaskIntoConstraints" sur toutes les vues que je crée dans mon programme.


 


Je procède en trois étapes:


 


1- Je crée un UIButton en bas de l'écran.


2- Je crée un UILabel, que je centre au milieu de l'écran.


3- J'applique une contrainte à  l'instance de UILabel pour le centrer au milileu de la page. => Le UILabel et le UIButton saute en haut de l'écran !


 


Je suis surpris par ce comportement. Je m'attendrais à  ce que le Layout Engine n'ait d'effets que sur les vues auxquelles une contraintes est attaché, et qu'il laisse tranquille toutes les vues qui ne sont pas concernées par les contraintes. Qu'en pensez vous?


 


Pour que nous soyons sur la même page: je colle ici le code et les screenshots correspondant à  chacune des trois étapes, pour que tout le monde puisses bien voir l'évolution de la position de l'instance de UIButton. En effet vous pourrez constater comme moi qu'il "saute de place" pour retourner en haut de page dès qu'une contrainte est appliquée sur l'instance de UILabel...


 


 


 


1- Je crée un UIButton en bas de l'écran.



//: Playground - noun: a place where people can play

import UIKit
import PlaygroundSupport

let liveview = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 600))

let button = UIButton(frame: CGRect(x: 123.5, y: 566, width: 50, height: 50))
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("BUTTON", for: .normal)
button.backgroundColor = UIColor.darkGray
button.sizeToFit()
liveview.addSubview(button)

PlaygroundPage.current.liveView = liveview


Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    Bref. Utiliser le code pour créer les vues, c'est comme se battre autour la tête avec un marteau.


    Essayes de faire la même chose dans un storyboard et le designer te montrera ce qu'il manque.
  • DrakenDraken Membre
    mai 2017 modifié #3


    Bref. Utiliser le code pour créer les vues, c'est comme se battre autour taper la tête avec un marteau.


    Essayes de faire la même chose dans un storyboard et le designer te montrera ce qu'il manque.




    J'allais le dire. Plonge-toi dans Storyboard. Non seulement c'est plus simple, mais tu pourras plus facilement créer des interfaces s'adaptant aux différents devices.


     


    Playground c'est bien pour apprendre les bases du langage (et encore). Mais rien ne vaut Storyboard pour créer des interfaces, avec des contrôles graphiques dans tous les sens.


  • ifouifou Membre

    Merci pour vos réponses à  tout deux.


     


    Je viens d'essayer dans Interface Builder. C'est marrant mais pour le coup, les deux vues sont restées à  leur place.


     


    J'ai rajouté une deuxième contrainte sur le label: pour le centre horizontalement et verticalement, et à  ce moment là  le bouton s'est retrouver propulser en haut de page.


     


    Cependant que ce soit via IB ou via Playground, la question reste entière: pourquoi le Layout Engine vient traficoter la vue sur laquelle je n'ai mis aucune contrainte?


  • DrakenDraken Membre


    Merci pour vos réponses à  tout deux.


     


    Je viens d'essayer dans Interface Builder. C'est marrant mais pour le coup, les deux vues sont restées à  leur place.


     


    J'ai rajouté une deuxième contrainte sur le label: pour le centre horizontalement et verticalement, et à  ce moment là  le bouton s'est retrouver propulser en haut de page.


     


    Cependant que ce soit via IB ou via Playground, la question reste entière: pourquoi le Layout Engine vient traficoter la vue sur laquelle je n'ai mis aucune contrainte?




    Pas la moindre idée .. Chez moi tout se passe normalement, quand je tente de reproduire ta manip avec Storyboard.


     


    Je vais te montrer image par image comment je procéde.

  • DrakenDraken Membre
    mai 2017 modifié #6


    Cependant que ce soit via IB ou via Playground, la question reste entière: pourquoi le Layout Engine vient traficoter la vue sur laquelle je n'ai mis aucune contrainte?




    Mais bien sur, c'est évident.. On a tellement l'habitude de manipuler les contraintes qu'on n'y pense plus. Dans ton code tu as rendu le bouton sensible aux contraintes, sans en définir aucune. Xcode ne sachant pas où placer le contrôle, il le colle dans le coin haut gauche de l'écran.


     


    Si tu rends le bouton sensible aux contraintes, il faut FORCEMENT des contraintes pour calculer sa position !



    button.translatesAutoresizingMaskIntoConstraints = false

    Si tu veux le positionner avec du code classique (frame), ne touche pas à  sa propriété translateAutoresizingMaskIntoConstraints !


  • Joanna CarterJoanna Carter Membre, Modérateur
    Si tu commences à  ajouter les contraintes, tu dois ajouter tout ce qu'il faut pour que l'engine puisse marcher correctement. C'est pour ça que je t'ai dit d'essayer le dans un storyboard pour voir les contraintes que t'as manqué.
  • DrakenDraken Membre

    Copie d'écran du Storyboard pour reproduire ta manip. J'ai utilisé deux contraintes pour centrer le label sur l'écran, et deux autres pour placer le bouton en bas de l'écran, comme sur tes images.


     


     


  • CéroceCéroce Membre, Modérateur
    mai 2017 modifié #9

    Alors, personnellement, créer les contraintes par le code m'a beaucoup aidé à  comprendre comment ça fonctionnait, même si je les crée autant que possible dans un Storyboard ou xib.


     


    Dans ton code, ce que je trouve étonnant, est qu'à  aucun moment tu n'appelles la méthode UIView.addConstraints(). À ce propos, tu verras que la contrainte doit être ajoutée à  la vue parente. Essaie aussi d'utiliser le "visual format".


     


    Enfin, le layout engine satisfait les contraintes comme il l'entend. Dans ton exemple, tu définis une contrainte horizontale sur le label pour qu'il soit centré, mais pas de contrainte verticale. Les contraintes sont respectées: ton label est bien centré horizontalement.


  • CéroceCéroce Membre, Modérateur


    Dans ton code, ce que je trouve étonnant, est qu'à  aucun moment tu n'appelles la méthode UIView.addConstraints().




    Grâce à  toi, je viens de découvrir la propriété .isActive qui appelle addConstraint() sur la vue parente. J'aurais appris quelque chose aujourd'hui.

Connectez-vous ou Inscrivez-vous pour répondre.