Comment "mixer" XIB et code ? (taille de la frame)

colas_colas_ Membre
août 2014 modifié dans API UIKit #1

Bonjour,


 


J'ai désigné un vue via IB (avec des sous-vues, des contraintes, etc.). Cette vue est associée à  un contrôleur.


 


Je voudrais savoir s'il est possible lors de l'initialisation du view controller de lui passer un CGRect frame en argument, qui déterminera la taille de la vue (et de toutes les sous-vues, en conséquence, grâce aux contraintes)


 


Pour l'instant, j'ai fait ceci, mais ça ne marche pas. Quand la vue est mise à  la bonne taille dans - viewDidLoad, les sous-vues qui devraient changer de taille (à  cause des contraintes), ne changent pas de taille.



- (id)initWithFrame:(CGRect)frame
{
self = [super initWithNibName:@MyXIB
bundle:nil] ;

if (self)
{
_frame = frame ;
}

return self ;
}

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.


/*
Managing sizes
*/
self.view.frame = self.frame ;
[self.view updateConstraints] ;


/*
Creating a sub view
*/
MySubviewController * vc = [[MySubviewController alloc] initWithFrame:CGRectMake(0,0,self.viewForSubView.frame.size.width, self.viewForSubView.frame.size.height)] ;

// problem here: the size self.viewForSubView is the size in the XIB, not the size following the constraints...
[self.viewForSubview addSubview:vc.view] ;
}


Une piste ?


 


Merci !

Réponses

  • AliGatorAliGator Membre, Modérateur

    A partir du moment où tu as choisi de définir des contraintes sur tes vues, tu ne peux pas mélanger l'utilisation des contraintes et des frames. Ca n'aurait pas de sens. Tu changes manuellement la frame d'une vue en lui donnant une valeur, mais ensuite le moteur de contraintes vient faire tous ses calculs et va remodifier la frame que tu aurais précédemment changé à  la main ! Donc ça ne sert à  rien de faire des "view.frame = xxx" puisqu'elles seront écrasées / recalculées par le moteur de contrainte.


     


    Si tu veux imposer par le code certaines dimensions, tu peux toujours mettre une contrainte sur la largeur et la hauteur de ta vue, par exemple dans le XIB, puis faire des IBOutlets dessus ("@property(weak) IBOutlet NSLayoutConstraint* widthConstraint" + "@property(weak) IBOutlet NSLayoutConstraint* heightConstraint") et ainsi tu pourras par code modifier la valeur de ces contraintes (widthConstraint.constant = self.bounds.size.width; heightConstraint.constant = self.bounds.size.height;) pour imposer les dimensions de ta vue. Non pas donc en changeant leur frame qui risquerait d'être rechangée par le moteur de contrainte, mais en imposant une valeur aux contraintes de largeur et hauteur de sorte que le moteur de contraintes prenne en compte ces dimensions que tu lui imposes quand il fait son calcul de layout.


  • Merci de ta réponse Ali !


     


    Le problème, c'est que je ne peux pas ajouter via IB de contrainte sur la hauteur et la largeur de la vue principale.


    Je vais essayer en ajoutant via le code les contraintes.


     


    Il faudra que je `self.view.translatesAutoresizingMaskIntoConstraints = NO ;`.


    À chaque fois que j'ai essayé de faire ça, ça donnait des comportements très bizarres. Ma nouvelle politique était : pas touche à  translateAutoresizing...


  • colas_colas_ Membre
    août 2014 modifié #4

    Je ne suis pas totalement d'accord avec ton point de vue.


     


    J'ai une vue avec pleine sous-vues. Les contraintes sont sur les sous-vues et sur le lien entre elles et la vue principale.


    Mon idée est de changer la taille de la vue principale et que tout se réorganiser "en dessous"...


     


    Après, si c'est comme ça que ça marche (ou que ça marche pas)... y'a qu'à  s'y faire !


  • Avec la méthode ci-dessous, ça marche. Merci !



    #import <UIKit/UIKit.h>

    @interface UIView (CBDHelperMethods)

    - (void)fillWithSubview_cbd_:(UIView *)view ;

    @end






    #import "UIView+CBDHelperMethods.h"

    @implementation UIView (CBDHelperMethods)


    - (void)fillWithSubview_cbd_:(UIView *)view
    {
    view.translatesAutoresizingMaskIntoConstraints = NO ;
    [self addSubview:view] ;

    UIView *superview = self.superview ;

    [superview addConstraint:[NSLayoutConstraint constraintWithItem:self
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:view
    attribute:NSLayoutAttributeTop
    multiplier:1.0
    constant:0]];

    [superview addConstraint:[NSLayoutConstraint constraintWithItem:self
    attribute:NSLayoutAttributeLeading
    relatedBy:NSLayoutRelationEqual
    toItem:view
    attribute:NSLayoutAttributeLeading
    multiplier:1.0
    constant:0]];

    [superview addConstraint:[NSLayoutConstraint constraintWithItem:self
    attribute:NSLayoutAttributeWidth
    relatedBy:NSLayoutRelationEqual
    toItem:view
    attribute:NSLayoutAttributeWidth
    multiplier:1.0
    constant:0]];

    [superview addConstraint:[NSLayoutConstraint constraintWithItem:self
    attribute:NSLayoutAttributeHeight
    relatedBy:NSLayoutRelationEqual
    toItem:view
    attribute:NSLayoutAttributeHeight
    multiplier:1.0
    constant:0]];

    [self updateConstraints] ;
    }


    @end
  • AliGatorAliGator Membre, Modérateur

    C'est tout à  fait ça !


    1) Passer translatesAutoresizingMaskIntoConstraints à  NO


    2) Ajouter les contraintes entre la superview et la subvue que tu viens de lui rajouter (pour lui expliquer comment se positionner par rapport à  son parent)


     


    Je t'invite à  regarder la session #14 des CocoaHeads (j'espère qu'elle est en vidéo ?) où Thomas expliquait une de ses astuces pour intégrer dans un XIB 1 un composant défini dans un XIB 2 (donc insérer une vue qui vient d'un XIB dans un autre XIB).


     


    Tu as dans tous les cas le code dispo sur le GitHub : https://github.com/CocoaHeads-Rennes/14-XibFromXib


     


    En particulier tu vois qu'il fais la même chose que toi ici dans sa classe Stepper donc tu peux t'en inspirer.


     


    Tu vois par exemple que plutôt que le gros paquet de lignes de code que tu mets pour ajouter tes 4 contraintes, tu peux le faire en 2 ou 3 lignes en utilisant le "Visual Format", c'est plus compact.


  • Finalement, il semble que ça marche !


    Il semble que oui, on peut mixer contraintes et frames.


     


    - J'ai un ViewController2 dont le contenu est géré par des contraintes.


     


    - J'ai ViewController qui ne gère aucune contrainte. J'ajoute dedans ViewController2, qui prend la taille qu'il avait dans son xib.


     


    - Puis, je change la frame de ViewController2. Alors, la vue change de taille ET les éléments à  l'intérieur respectent les contraintes.


     


    TROP COOL !!


     


    @Ali : dans ton message #2 que cette réponse semble contredire, je pense que tu parlais d'un autre cas. Celui où ViewController2 est placé dans ViewController via des contraintes MAIS qu'on essaie de forcer sa frame.


     


    Un petit toy project qui démontre cela :


     


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