UIImagePickerViewController qui resize ma vue en dessous

Bonjour à  tous,


 


J'ai un petit soucis avec un imagePickerViewController qui permet de prendre ou sélectionner une photo. Actuellement j'ai une UIViewController avec une frame personnalisée (on prendra ici (0, 0, 100, 100)). Lorsque je présente le imagePickerViewController, et que je le referme, ma viewController avec frame personnalisée prend la taille de l'écran entier et a perdu ses dimensions d'origine.


J'avais donc penser à  rétablir les dimensions ici :



picker.dismissViewControllerAnimated(true, completion: { () -> Void in
// Rétablir la frame d'origine
}

Sauf que la frame se rétablit une fois que le picker a complètement disparu de l'écran, ce qui est logique. Serait-il possible de faire reprendre la taille d'origine à  ma viewController au moment où l'utilisateur dismiss le imagePickerViewController ?


 


Merci d'avance


Réponses

  • Tu repasses pas dans le viewwillappear ? (Il me semble que oui, du coup tu peux faire ton reframing ici)


  • BenjoBenjo Membre
    août 2015 modifié #3

    Oui oui je passe bien dans viewWillAppear(). Mais j'ai essayé de lui assigner les dimensions (0, 0, 10, 10) :



    override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(true)

    self.view.frame = CGRectMake(0, 0, 10, 10)

    Rien à  faire elle reste en plein écran...


  • Et dans le viewDidLayoutSubviews ? (ou viewWillLayoutSubviews)


     


    Ou encore un  [self.view layoutIfNeeded]

  • AliGatorAliGator Membre, Modérateur
    C'est quoi ses NSLayoutConstraints à  ta vue parente ?
  • Alors la solution de Geoffrey marche plus ou moins bien. C'est à  dire qu'au début, lorsque ma viewController apparait (avec la bonne taille comme il faut) j'ai ce résultat (voir pièce jointe n°1). Puis une fois la photo sélectionnée, je me retrouve avec (voir pièce jointe n°2) ma navigationBar qui dépasse complètement de ma viewController alors que celle-ci est correctement resizé.


     


    AliGator, je ne comprend pas ce que tu veux exactement... Je n'ai attribué aucun constraint à  ma vue parente enfin rien de plus que ceux attribués de base j'imagine. Alors ou j'ai mal compris où je ne sais pas ce qu'il faut chercher :/


  • AliGatorAliGator Membre, Modérateur

    Je n'ai attribué aucun constraint à  ma vue parente

    Ah bah c'est p'tet ça le problème alors !


  • Ah bah c'est p'tet ça le problème alors !




    C'est fort possible. En fait, je ne savais pas que je pouvais attribuer des constraints à  une viewController depuis storyboard.


     


    De base, j'ai ma viewController principale avec un bouton. Lorsque je clique sur ce bouton, j'utilise "UIViewControllerAnimatedTransitioning" pour créer une transition customisée vers mon autre vue. Je lui assigne donc sa taille. Mais à  aucun moment je ne lui donne des constraints.


    J'ai oublié de dire que ma seconde viewController était imbriquée dans un NavigationController.


    C'est donc ça le problème ?

  • Je me suis renseigné un peu du coté de autoLayout avec des vue parente. J'aimerais poser deux questions :


    - Peut-on attribuer des constraints à  une vue enfant ?


    - Si oui, de quelle manière ?


  • AliGatorAliGator Membre, Modérateur
    Je ne comprend pas trop la question. Avec AutoLayout, tu mets des contraintes entre les vues. Dire que tu mets une contrainte entre la vue parente et une de ses vues fille, c'est pareil que dire que tu mets une contrainte entre une vue fille et sa vue parente...
  • Ha ok je pense avoir compris le truc. En gros il faut que j'arrive à  mettre des contraintes entre la vue fille et parente. Arriver à  dire, par exemple, que ma vue fille garde telle largeur, telle hauteur, etc. C'est ça ?


  • Bon je ne sais pas du tout si je suis sur la bonne voie, mais j'ai essayé quelque chose. Une fois que ma vue fille est apparue, que l'animation est terminée, j'ai tenté de mettre une contrainte en largeur de 100. J'ai donc essayé ceci :



    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

    if self.presenting == true {
    /*
    Ici on configure l'animation d'apparition
    */
    UIView.animateWithDuration(animationDuration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
    // On execute l'animation

    }, completion: { (finished) -> Void in
    // On ajoute les constraints
    let widthConstraint = NSLayoutConstraint(item: toViewController!.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
    toViewController?.view.addConstraint(widthConstraint)

    transitionContext.completeTransition(true)
    })
    }
    }

    Mais j'ai toujours ce même problème lors du retrait du imagePicker et ma viewController perd la contrainte que je lui ai assignée. J'avoue être un peu perdu... je ne sais pas vraiment dans quelle direction m'orienter. J'ai vraiment besoin d'un peu d'aide pour me mettre sur la bonne voie.


     


    Merci d'avance


  • AliGatorAliGator Membre, Modérateur
    Alors déjà , je ne connais pas trop le look de ton UI et pourquoi ta vision c'est plutôt "j'impose une largeur de 100" (pourquoi 100 et pas 120 ou 80 ?), plutôt que "ma vue fait toute la largeur de sa vue parente" ou "la vue fille fait 1/3 de la largeur de sa vue parente" " car bon on est quand même dans un monde où la taille des écrans est loin d'être fixe aujourd'hui entre les différentes tailles d'iPhone, le changement d'orientation possible, SlideOver et SplitView... du coup mettre des tailles en dur c'est plus trop une bonne idée, AutoLayout ou pas.


    Moi j'aurais plutôt collé les bords gauche, droite, haut, bas de la vue fille aux bords correspondants de la vue parente et laisse sa largeur & hauteur flexible. Chose que tu peux faire, au choix, avec les AutoResizingMask à  l'ancienne, ou avec AutoLayout. Mais quelle que soit la solution choisie l'idée est simplement de dire à  iOS "voilà  comment ma vue fille doit se redimensionner quand sa vue parente de redimensionne " ou qu'elle recalcule le layout de ses subviews pour toute autre raison.
  • BenjoBenjo Membre
    août 2015 modifié #14

    Merci AliGator pour ta réponse. En fait, j'avais testé juste de mettre une contrainte de 100 sur la largeur juste pour essayer et voir surtout si c'était disons la bonne chose à  faire. Bien sûr que je ne ferais pas ça c'était juste pour tester l'ajout d'une contrainte.


     


    Sinon merci pour les conseils ça m'aide bien. Donc j'ai prévu les contraintes suivantes :


    - Centrer en X avec la vue parente


    - Bord gauche et droit collés avec 5px de décalage


    - Haut collé avec 5px de décalage


    - Hauteur de 200


     


    J'ai donc essayé d'ajouter la première contrainte (center x) :



    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

    if self.presenting == true {
    /*
    Ici on configure l'animation d'apparition
    */
    UIView.animateWithDuration(animationDuration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in
    // On execute l'animation

    }, completion: { (finished) -> Void in
    // On ajoute les contraintes
    toViewController?.view.setTranslatesAutoresizingMaskIntoConstraints(false)

    let verticalCenter = NSLayoutConstraint(item: toViewController!.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: fromViewController!.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)

    toViewController?.view.addConstraints([verticalCenter])

    transitionContext.completeTransition(true)
    })
    }
    }

    Mais directement je me retrouve avec un crash juste après l'apparition de ma vue fille : "Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Impossible to set up layout with view hierarchy unprepared for constraint" J'ai pas mal cherché sur le web. Sur SO je n'ai rien trouvé qui puisse m'aider. je ne crois pas que ça vienne de ma contrainte qui est mal configurée, mais plutôt que l'ajout des contraintes n'est pas fait au bon moment.


    Pour simplifier les choses, j'ai fait un schéma de mon UI (voir pièce jointe).


    J'espère que cela vous aidera un peu plus.


     


    Merci d'avance.


    UI.png 38.2K
  • AliGatorAliGator Membre, Modérateur
    Effectivement tes contraintes me paraissent bonnes et cohérentes, mais les faire à  cet endroit dans le code n'est sans doute pas le bon endroit.
    Déjà  il ne fait mettre des contraintes à  une vue qu'une fois qu'elle a été rajoutée dans la hiérarchie de vue, pas avant (= faire le addSubview avant de rajouter les contraintes donc)
    Ensuite, je ne les ferais personnellement pas dans le mécanisme du UIViewControllerTransitioning mais plutôt quand tu ajoutes la vue, dès le début.
    Pense par exemple que l'utilisateur peut tout à  fait demander un "presentViewController(..., animated: false)" pour que le ViewController soit affiché directement sans animation, et dans ce cas ta transition custom ne sera pas exécutée, mais il ira directement au résultat final, où il faut pourtant qu'il y ait aussi les contraintes de placées.
  • Ha oui effectivement je n'avais pas pensé aux options d'accessibilité merci AliGator. Mais je sais surement d'où vient mon crash : je n'ajoute pas la vue fille à  ma vue parente mais dans le containerView lors de la transition. Je m'y prenait donc comme ceci :



    fromViewController?.view.userInteractionEnabled = false

    transitionContext.containerView().addSubview(fromViewController!.view)
    transitionContext.containerView().addSubview(toViewController!.view)

    // On configure la position de départ
    toViewController?.view.frame = CGRectMake(fromViewController!.view.frame.width / 2 - 30, fromViewController!.view.frame.height - 60 - 20, 60, 60) //Ces magics numbers ne sont pas définitifs
    toViewController?.view.layer.cornerRadius = 4
    toViewController?.view.layer.masksToBounds = true

    // On arrondis les coins
    let animation = CABasicAnimation(keyPath: "cornerRadius")
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
    animation.fromValue = 30
    animation.toValue = 4
    animation.duration = animationDuration
    toViewController?.view.layer.addAnimation(animation, forKey: "cornerRadius")

    UIView.animateWithDuration(animationDuration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in

    // On rend la vue de dessous noir
    fromViewController?.view.alpha = 0.5

    // On modifie la position de la vue de publication
    toViewController?.view.frame = CGRectMake(5, 5, fromViewController!.view.frame.width - 10, fromViewController!.view.frame.width - 10)
    }, completion: { (finished) -> Void in
    // On ajoute les contraintes
    toViewController?.view.setTranslatesAutoresizingMaskIntoConstraints(false)

    let verticalCenter = NSLayoutConstraint(item: toViewController!.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: fromViewController!.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)

    toViewController?.view.addConstraints([verticalCenter])

    transitionContext.completeTransition(true)
    })

    Et je pense surtout que mon problème de contrainte vient du "transitionContext.containerView().addSubview(toViewController!.view)" ce qui expliquerai le problème de hiérarchie.


     


    En fait, je crois que je m'y prend juste mal pour ma transition custom. Je vais essayer de me renseigner un peu plus du coup car le problème vient finalement de la façon dont je m'y prend pour ma transition.


  • Après de très longues heures passées sur le net à  chercher d'où provenait mon erreur, je n'ai toujours rien trouvé... J'ai essayé comme tu s dit AliGator d'ajouter mes contraintes juste après le addSubview(). J'ai également essayé de configurer ma contrainte en fonction de la vue container plutôt caves la fromView :



    transitionContext.containerView().addSubview(fromViewController!.view)
    transitionContext.containerView().addSubview(toViewController!.view)

    // On ajoute les contraintes
    toViewController?.view.setTranslatesAutoresizingMaskIntoConstraints(false)

    let verticalCenter = NSLayoutConstraint(item: toViewController!.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem:transitionContext.containerView(), attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)

    toViewController!.view.addConstraints([verticalCenter])

    Rien n'y fait également je me retrouve toujours avec ce crash. Merci en tout cas pour votre aide j'ai déjà  bien avancé. Mais j'aurais besoin d'un petit coup de pouce supplémentaire.


     


    Merci d'avance.


  • BenjoBenjo Membre
    août 2015 modifié #18

    Bonjour à  tous,


     


    Bon finalement j'ai fini par trouver mon problème qui était des plus stupides : ma vue fille est imbriquée dans un navigationController. Ce qui fait que forcément j'avais un crash disant que les vues utilisées pour mes contraintes n'étaient pas de la même hiérarchie. Du coup il suffisait simplement de mettre les contraintes sur le "self.navigationController.view" et tout fonctionne normalement, sans crash.


     


    Merci pour votre aide :)


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