Faire qu'une vue remplisse une autre avec AutoLayout

CéroceCéroce Membre, Modérateur
Bonjour à  tous,



Je cherche à  faire quelque chose de très simple: faire en sorte qu'une vue enfant emplisse constamment sa vue parente. Constamment voulant dire, y compris après une rotation.



Voici comment je fais avec l'autoresizing mask:
UIView *cardView = self.cardViewController.view;<br />
			cardView.frame = CGRectMake(0.0f, 0.0f, self.cardPlaceholderView.frame.size.width, self.cardPlaceholderView.frame.size.height);<br />
			[self.cardPlaceholderView addSubview:cardView];<br />
			cardView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;<br />




ça fonctionne.

Ma question: Comment obtenir le même fonctionnement avec l'auto-layout?



Déjà , dans CardViewController.xib, je ne peux pas ajouter de contraintes à  cardView.

J'ai essayé ça, mais une exception est lancée:
NSDictionary *viewDict = NSDictionaryOfVariableBindings(cardView);<br />
			NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@&quot;V:|-0-[cardView]-0-|&quot; options:0 metrics:nil views:viewDict];<br />
			[cardView addConstraints:constraints];<br />



*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.




Ou alors, est-ce mon approche qui est totalement fausse ? Devrais-je ne pas ajouter cardView à  cardPlaceHolderView, mais directement cardView dans la vue parente?

Réponses

  • Je ne sais pas si je suis réfractaire au changement mais l'autolayout, je n'ai pas encore réussi à  franchi le pas. A chaque tentative, j'ai vu plus d'inconvénients que d'avantages...
  • Faut ajouter les constraint à  la superview, pas à  la cardview.
  • CéroceCéroce Membre, Modérateur
    novembre 2012 modifié #4
    @AP

    Je crois qu'Apple s'est fourvoyée sur ce coup là . On avait un système simple, avec une seule propriété autoResizingMask. On se retrouve avec 21 (!) nouvelles méthodes sur UIView, un Cocoa Auto Layout Guide, et un tas de nouveaux concepts dont on saisit mal l'enchevêtrement, même après visionné la vidéo de la WWDC. Je comprends le besoin, mais la solution me paraà®t incroyablement complexe.



    @Jegnux:

    OK, mais quelles contraintes? D'après ce que je vois dans la doc, les contraintes s'expriment plutôt par rapport aux vues parentes et aux vues soe“urs.
  • AliGatorAliGator Membre, Modérateur
    novembre 2012 modifié #5
    Les constraints s'expriment par rapport à  ce que tu veux du moment que toutes les vues entre lesquelles tu mets des contraintes sont dans la même Window. Justement c'est une des différences avec AutoResizingMask c'est qu'avec AutoLayout, tu peux tout à  fait mettre une contrainte entre une vue et la cousine de la grand-mère de la tante de cette vue.



    Pour ton cas ton VisualFormat est bon (bien que la forme plus compacte "|[cardView]|" sans les "-0-" serait aussi simple) mais il faut toujours associer une contrainte au parent commun à  toutes les vues en présence, donc dans ton cas à  ta vue parente de cardView et non à  cardView elle-même. D'où l'exception.



    De plus, n'oublie pas de désactiver la traduction automatique des autoresizingMasks existants en LayoutConstraints, car à  partir du moment où tu utilises les contraintes sur une vue iOS va automatiquement tout traduire en contrainte, y compris les autoresizingMasks existants, ce qui est très pratique pour pouvoir faire une transition en douceur des autoresizingMasks vers les LayoutConstraints et pouvoir mélanger les deux (surtout si tu as une appli existante qui utilisait les AutoResizingMasks avant et que tu veux la migrer progressivement)... mais du coup si tu laisses ce fonctionnement pour ta vue à  qui tu rajoutes des contraintes tu vas avoir tes contraintes + celles de l'AutoLayout qui vont se cumuler sur cette vue et vont entrer en conflit.

    Donc il faudra utiliser [cardView setTranslatesAutoresizingMaskIntoConstraints:NO] pour éviter les conflits sur cette vue, sinon tu auras une exception (différente de ton actuelle) qui va te dire que tu as des "Insatisfiable Constraints".



    Je t'invite à  consulter la conf CocoaHeads de Rennes de Jeudi dernier où Thomas expliquait tout cela en détail ;-)
  • CéroceCéroce Membre, Modérateur
    OK. Je n'ai pas encore jeté un oe“il à  la présentation de Thomas, mais elle doit se trouver dans ma liste de lecture Safari!
  • le lien de la conf svp car sa m'intresse
  • AliGatorAliGator Membre, Modérateur
    La session à  été annoncée ici sur le site des CocoaHeads mais je pense que la session vidéo et les solides n'ont pas encore été misés en ligne après la conf.

    ISofTom vous préviendra sûrement quand ça sera dispo sinon ;-)
  • merci ali
  • En tout cas l'AutoLayout c'est tout sauf intuitif, je ne me suis pas sérieusement penché sur la question mais dès que j'essaye de sortir un peu des sentiers battus, cela ne marche pas.



    Via le storyboard c'est quand même un peu le bazard. On se retrouve vite avec 50.000 contraintes, qui se mettent toutes seules, parfois inutiles lorsqu'on a déplacé plusieurs fois certains éléments de l'interface.



    Ne serait-ce qu'avoir une vue dans laquelle j'ai une tableView qui occupe une partie de l'écran qui s'agrandit pour remplir la place lorsqu'il s'agit d'un iPhone 5, je n'y arrive pas. Il faudra que je me plonge un jour vraiment dedans car c'est tout sauf intuitif.
  • CéroceCéroce Membre, Modérateur
    N'y parvenant pas, j'ai jeté un oe“il à  l'une des vidéos de la WWDC.

    Comme le disais Ali, mais que j'avais compris de travers ;-) si on ne veut pas d'ennui, il faut appeler setTranslatesAutoresizingMaskIntoConstraints:NO. J'ai pensé qu'à  partir du moment où on disait que le XIB utilisait l'autolayout, c'était le cas. Je me trompais.

    Si on le laisse à  YES, des contraintes sont ajoutées automatiquement, et on obtient un message d'erreur disant qu'on ne peut satisfaire des contraintes antagonistes.



    ça donne donc ceci: (avec une marge de 12 points):
    <br />
    UIView *cardView = self.cardViewController.view;<br />
    [cardView setTranslatesAutoresizingMaskIntoConstraints:NO];<br />
    [self.cardPlaceholderView addSubview:cardView];<br />
    NSDictionary *variablesDict = NSDictionaryOfVariableBindings(cardView);<br />
    NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@&quot;H:|-(12)-[cardView]-12-|&quot; options:0 metrics:nil views:variablesDict];<br />
    [self.cardPlaceholderView addConstraints:hConstraints];<br />
    NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@&quot;V:|-(12)-[cardView]-12-|&quot; options:0 metrics:nil views:variablesDict];<br />
    [self.cardPlaceholderView addConstraints:vConstraints];<br />
    




    Au départ, je n'avais fixé qu'une contrainte horizontale. La hauteur était mise à  0! Voilà  qui me semble bien étrange. Ajouter une contrainte verticale semble donc nécessaire. En tout cas, ça fonctionne.



    Merci Ali!
  • AliGatorAliGator Membre, Modérateur
    Bah oui l'intérêt quand tu utililises AutoLayout c'est de ne plus du tout avoir à  faire de setFrame dans ton code. Tu ne spécifies plus aucune frame, tout se fait par l'AutoLayout.



    Et du coup si tu ne mets aucune contrainte verticale, c'est logique que la hauteur de ta vue n'étant ni spécifiée ni contrainte sera du coup égale à  0 image/wink.png' class='bbc_emoticon' alt=';)' />



    C'est vrai que la toute première fois qu'on voit AutoLayout on est un peu obligé de tomber dans les 2 pièges de base dans lesquels tu es tombé Céroce (ajouter les contraintes à  la bonne vue + penser à  désactiver la traduction des AutoResizingMask en LayoutConstraints pour éviter les conflits de contraintes.



    Mais toutes les vidéos (surtout celles de la WWDC, très bien faites) expliquent ça en détail, et une fois qu'on est passé outre ces 2 points, cela devient assez propre et plus logique à  comprendre.
Connectez-vous ou Inscrivez-vous pour répondre.