Autolayout + UIViewController + Rotation

muqaddarmuqaddar Administrateur

Salut,


 


Je suis dans le dur avec Autolayout en ce moment.  ::)


 


J'ai un VC, qui contient une vue partielle.


Celle vue ajoute soit:


- la tableView d'un autre VC


- la vue d'un UIPageViewController


 


Je n'ai aucun soucis avec la tableView: quand je fais une rotation du device, tout s'étire ou se rétrécit et tout colle aux bords.


 


Le problème est pour le PageViewController: la vue n'est pas adaptée après rotation (ou même à  certains lancements), elle garde sa dimension d'origine, il faut la recharger pour que ça marche. Je ne pense pas que ce comportement soit normal.


 


Structure:


 


Dans mon VC d'origine:



    self.pagesViewController.view.frame = self.dataView.bounds;
    [self.dataView addSubview:self.pagesViewController.view];

Dans pagesViewController (hérite de VC et a un outlet vers UIPageViewController *pageViewController):



    // manage the pageViewController
    [self addChildViewController:self.pageViewController];
    [self.view addSubview:self.pageViewController.view];
    [self.pageViewController didMoveToParentViewController:self];

Dans pageViewController, rien de spécial, je définis les contraintes des sous-vues dans IB: ces contraintes sont bien prises en compte, le problème est en amont.


 


 


Réponses

  • AliGatorAliGator Membre, Modérateur
    Et o`ajoutes-tu tes contraintes entre le dataView conteneur et la vue que tu mets dedans (tableView ou pageViewController), de sorte que si la dataView est redimentionnée sont contenu (sa subview) suive ?

    Sinon je t'invite à  utiliser le nouveau mode de Xcode6 pour déboguer les interfaces (vue éclatée / 3D) avec affichage des contraintes)
  • muqaddarmuqaddar Administrateur


    Et o`ajoutes-tu tes contraintes entre le dataView conteneur et la vue que tu mets dedans (tableView ou pageViewController), de sorte que si la dataView est redimentionnée sont contenu (sa subview) suive ?




     


    C'est la question que je me suis posée.


     


    Pour la tableView, les contraintes sont dans le VC associé (dans IB).


     


  • AliGatorAliGator Membre, Modérateur
    Tu n'as pas compris ma question je pense.

    Tu as des contraintes entre les vues de ton VC parent.
    Tu as des contraintes à  l'intérieur de ta vue qui contient ta UITableView.

    Mais je ne vois pas où tu as mis des contraintes entre ta self.dataView et ton self.pageViewController.view.

    C'est bien beau de faire un [self.dataView addSubview:self.pageViewController.view] mais quand tu fais ça il faut peut-être ajouter des contraintes ensuite entre l'un et l'autre, pour que la taille du self.pageViewController.view suive en permanence la taille de la self.dataView !

    Je te dis, utilises le nouveau débugueur d'UI d'Xcode6 tu vas comprendre.
  • muqaddarmuqaddar Administrateur

    SI j'ai compris ta question et j'y ai même répondu.


     


    Je ne vois pas, comment donner les contraintes entre la vue de pagesViewController et sa superview dataView, dans IB du moins... Faut-il passer par le code obligatoirement ?


     


    J'ai utilisé la fonction view debug de Xcode 6 (mais ça ne m'a rien appris car je sais que la sous-vue rouge ne prend pas la taille de la superview bleue, j'utilise les couleurs quand j'ai des bugs de cet accabit). Par contre, je me suis payé 2 Kernel Panic grâce à  cette feature de Xcode !


     


     


     


  • AliGatorAliGator Membre, Modérateur
    juin 2014 modifié #6

    Je ne vois pas, comment donner les contraintes entre la vue de pagesViewController et sa superview dataView, dans IB du moins... Faut-il passer par le code obligatoirement ?

    Alors pour moi pour ce cas précis, oui je ferai par code, je ne vois pas trop comment faire autrement puisque pendant que tu es dans IB, tes 2 vues (la vue contenante et la vue contenu) sont séparées et ne sont pas encore l'une à  l'intérieur de l'autre. Donc je ne vois pas comment à  ce stade dans IB tu pourrais affecter des contraintes.

    Et de toute façon quand tu enlève une UIView de sa superview, les contraintes qu'il y avait entre ces vues sont supprimées au passage (et encore heureux, car si après tu décidais d'ajouter cette UIView en subview à  une autre superview qui n'a rien à  voir avec la première, faudrait pas qu'il essaye de satisfaire des contraintes avec la première !!). Donc quand tu rajoutes une UIView en subview à  une autre il faut aussi créer les contraintes qui vont avec.
     
    ...
    // Ajout de la vue du PageViewController en subview
    UIView* pageView = self.pageViewController.view
    [self.view addSubview:pageView];

    // Ajout des contraintes
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@H:|[pv]| options:0 metrics:nil views:@{@pv:pageView}]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@V:|[pv]| options:0 metrics:nil views:@{@pv:pageView}]];
     

    J'ai utilisé la fonction view debug de Xcode 6 (mais ça ne m'a rien appris car je sais que la sous-vue rouge ne prend pas la taille de la superview bleue, j'utilise les couleurs quand j'ai des bugs de cet accabit). Par contre, je me suis payé 2 Kernel Panic grâce à  cette feature de Xcode !

    Oups, ah ouais quand même ! Le genre de truc que j'ai pas vu depuis des lustres sur OSX ! BugReport d'urgence !
  • AliGatorAliGator Membre, Modérateur
    juin 2014 modifié #7

    Structure:
     
    Dans mon VC d'origine:

        self.pagesViewController.view.frame = self.dataView.bounds;
        [self.dataView addSubview:self.pagesViewController.view];
    Dans pagesViewController (hérite de VC et a un outlet vers UIPageViewController *pageViewController):
        // manage the pageViewController
        [self addChildViewController:self.pageViewController];
        [self.view addSubview:self.pageViewController.view];
        [self.pageViewController didMoveToParentViewController:self];

    En relisant ton code dans ton premier post je viens de tiquer, c'est bizarre ce que tu fais, pourquoi tu ajoutes ton self.apgesViewController en subview à  2 endroits, à  la fois dans ton parent et dans le fils ?

    Tu as du coup de ce que je comprends 3 niveaux de UIViewController (et non pas 2 comme je l'avais compris de premier abord) :
    1. Un UIViewController parent
    2. Un UIViewController enfant, contenant un IBOutlet vers un UIPageViewController
    3. Cet UIPageViewController donc.

    Sauf que entre 1 et 2 tu ne fais qu'un ajout de subview sans faire un ajout de childViewController. Alors qu'entre 2 et 3 tu fais bien cet ajout de childViewController en + de l'ajout de subview... Pourquoi cette inconsistance / asymétrisme dans ton code ? Et du coup, ça veut dire si tu as 2 niveaux qu'il te manque les contraintes à  la fois entre 1 et 2 et entre 2 et 3, non ?
  • muqaddarmuqaddar Administrateur


    Sauf que entre 1 et 2 tu ne fais qu'un ajout de subview sans faire un ajout de childViewController. Alors qu'entre 2 et 3 tu fais bien cet ajout de childViewController en + de l'ajout de subview... Pourquoi cette inconsistance / asymétrisme dans ton code ? Et du coup, ça veut dire si tu as 2 niveaux qu'il te manque les contraintes à  la fois entre 1 et 2 et entre 2 et 3, non ?




     


    Je crois que c'est exactement ça. J'ai essayé d'être précis dans mon premier post.


     


    1. J'ai un VC qui a une dataView partielle (qui peut intégrer plein de vues de différents types).


     


    2. Cette dataView ajoute la vue du VC "enfant" (pagesViewController) (je n'ai pas besoin d'ajouter de contraintes ici normalement) :



    self.pagesViewController.view.frame = self.dataView.bounds;
    [self.dataView addSubview:self.pagesViewController.view];

    3. Dans le VC enfant, j'ai un outlet vers un pageViewController qui gère des VC enfants.


     


    Il y aurait bien en effet 2 niveaux de contraintes, ce qui fait que je suis un peu perdu, entre 1 et 2 et entre 2 et 3. Reste à  savoir où bien les mettre dans la hiérarchie.



       // Ajout de la vue du PageViewController en subview
        UIView* pageView = self.pageViewController.view;
        [self.view addSubview:pageView];
        
        // Ajout des contraintes entre pagesViewController et pageViewController
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@H:|[pv]| options:0 metrics:nil views:@{@pv:pageView}]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@V:|[pv]| options:0 metrics:nil views:@{@pv:pageView}]];
        
        // manage the pageViewController
        [self addChildViewController:self.pageViewController];
        [self.pageViewController didMoveToParentViewController:self];
        
        // get startingViewController
        WinePageViewController *startingViewController = [self viewControllerAtIndex:0];
        NSArray *viewControllers = [NSArray arrayWithObjects:startingViewController, nil];
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

        // Ajout des contraintes entre pageViewController et tous les VC "sous-enfants"
        [self.pageViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@H:|[pv]| options:0 metrics:nil views:@{@pv:startingViewController.view}]];
        [self.pageViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@V:|[pv]| options:0 metrics:nil views:@{@pv:startingViewController.view}]];
  • AliGatorAliGator Membre, Modérateur
    Question : pourquoi tu as besoin du niveau entre 2 et 3 ? Pourquoi ton pagesViewController est un UIViewController contenant un UIPageViewController en IBOutlet, plutôt que d'hériter directement de UIPageViewController lui-même ? (il y a sûrement une raison, mais bon)

    Et sinon, décompose le problème à  chaque niveau.
    - Quand 1 ajoute le VC enfant 2 en subview, c'est lui qui ajoute des contraintes entre 1 et 2 (dans la foulée du addSubview).
    - Quand 2 ajoute son UIPageViewController 3 en fils avec un addSubview, c'est lui qui ajoute les contraintes. Quoique pour lui, si ce VinoPagesViewController est défini à  l'aide d'un XIB, il y a là  sans doute moyen d'ajouter les contraintes via IB entre la UIView à  la racine du XIB (la vue du VinoPagesViewController / File's Owner) et la UIView de ton UIPageViewController que tu as mis dedans.



    Au final la relation 2-3 n'a rien d'exceptionnelle, c'est du classique dans IB. Si j'ai bien compris dans ton XIB tu as une UIView qui contient la vue du UIPageViewController et tu mets des contraintes dessus. Donc dans ce cas, pas besoin de code là  dessus si pour le [2 addSubview:3] ni pour ajouter une contrainte entre 2 et 3, tu peux tout faire dans IB comme tu fais d'habitude.

    Par contre, la relation 1-2 elle est dynamique (ton dataView contient une subview qui va différer selon les cas, pour afficher tantôt une UITableView et tantôt ton pagesViewController) et donc pour elle là  tu vas forcément faire les [1 addSubview:2] par code (car tu dois certainement avoir une condition pour ajouter tantôt la tableview, tantôt le pagesVC j'imagine). Et là  puisque tu fais le addSubview par code, il faut que tu fasses les contraintes entre 1 et 2 par code aussi.
  • muqaddarmuqaddar Administrateur


    Question : pourquoi tu as besoin du niveau entre 2 et 3 ? Pourquoi ton pagesViewController est un UIViewController contenant un UIPageViewController en IBOutlet, plutôt que d'hériter directement de UIPageViewController lui-même ? (il y a sûrement une raison, mais bon)




     


    Il y avait une raison, j'utilisais dans la V1 un autre système que UIPageViewController dans lequel j'avais besoin de ce niveau intermédiaire.


     


    Donc, je viens de le supprimer et pagesViewController hérite directement de UIPageViewController.


     


    Du coup, effectivement, je n'ai plus aucun problème d'autolayout et je dois ne rajouter aucun code !


     


    Par contre, je perds le comportement du UIPageViewController: on ne peut plus naviguer.


     


    Je dois délocaliser les méthodes de UIPageViewController datasource/delegate de VC2 vers VC1. C'est sûrement pour cette raison que j'avais gardé ce niveau intermédiaire: avoir tout ce qui se rapportait au UIPageViewController isolé dans VC2, au lieu de surcharger VC1.

  • muqaddarmuqaddar Administrateur
    juin 2014 modifié #11

    Bon, j'ai réussi à  garder mon niveau intermédiaire VC 2 (pour je le rappelle y exposer les méthodes delegate et datasource du UIPageViewController à  la place de VC1).


     


    Par contre, j'ai créé le UIPageViewController par le code:



      self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
      self.pageViewController.delegate = self;
      self.pageViewController.dataSource = self;
      [self.view addSubview:self.pageViewController.view];

    à  la place de l'outlet dans le XIB.


     


    Au final, j'ai:


    - un VC isolé (pour ne pas être dérangé) qui gère les pages


    - l'autolayout qui marche enfin sans code supplémentaire !


     


    Il reste que je ne comprends pas pourquoi l'outlet sur le UIPageViewController "foirait tout". Sûrement un mystère dans le XIB.


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