[Obj-C] Problème d'animation

Ben77650Ben77650 Membre
juillet 2018 modifié dans API UIKit #1

Hello,

Voila je viens à vous car j'ai un petit souci niveau animation que je n'arrive pas à comprendre (et mes collègues non plus).

J'essaye de déplacer un bouton grace à une animation (et également passer en opacité 0 certains éléments), puis à la fin de cette animation je lance une seconde animation pour changer la taille de mon bouton, et retirer le titre du bouton.

Cette animation se fait en tant qu'IBAction sur le bouton que je souhaite bouger

Voila ma manière de faire :

[UIView animateWithDuration:2.0 animations:^{

    self.firstThemeButton.frame = CGRectMake(self.view.center.x - self.firstThemeButton.frame.size.width / 2,
                                             self.view.center.y - self.firstThemeButton.frame.size.height / 2,
                                             self.firstThemeButton.frame.size.width,
                                             self.firstThemeButton.frame.size.height);

    self.titleLabel.alpha = 0;
    self.descLabel.alpha = 0;
    self.separatorView.alpha = 0;
    self.logoImageView.alpha = 0;
    self.arrowImageView.alpha = 0;

}];

[UIView animateWithDuration:0.5 delay:2.0 options:0 animations:^{

    [self.firstThemeButton setTitle:@"" forState:UIControlStateNormal];

    self.firstThemeButton.frame = CGRectMake(self.view.center.x - self.firstThemeButton.frame.size.width / 2,
                                             self.view.center.y - self.firstThemeButton.frame.size.height / 2,
                                             self.firstThemeButton.frame.size.width,
                                             self.firstThemeButton.frame.size.height * 2);

} completion:nil];

Lors de mon 1er clic il me passe bien mes éléments en alpha 0 et il me retire bien mon titre sur le bouton.

Mais niveau animation, je vois disparaitre et s'afficher à sa position initiale (pas celle définie dans l'animation) et concernant sa taille elle ne change pas non plus.

En revanche si je clique une 2e fois, le bouton se met bien à la bonne position et se retaille bien.

Je ne pense pas que ça joue (puisque j'ai essayé en les retirant mais ça n'a rien changé) mais j'ai des contraintes sur ce bouton.

Merci aux âmes charitables qui me liront et qui m'aideront.

Bonne journée à tous.

Mots clés:

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    juillet 2018 modifié #2

    Si tu as mis les contraintes pour positionner le bouton, tu auras un conflit entre les contraintes et ton dimensionnement manuel.

  • Quand on enchaine les animations il est de bon ton de lancer la suivante dans le completionBlock de la précédente. Parce que rien ne peut t'assurer que :
    1. Ta première animation démarre tout de suite.
    2. Ta deuxième animation démarre pile 2 secondes après.

    Vu la manière dont CoreAnimation est construit ça peut poser un tas de soucis. Pour faire simple part toujours du principe que tout ce qui est asynchrone (animations, appels réseau, etc...) doit être considéré comme totalement détaché de ton main thread (en fait c'est clairement le cas).
    Ce qui veut dire que tu peux écrire les functions dans l'ordre que tu veux rien ne t'assure que ça sera l'ordre d'exécution. À moins de synchroniser les appels grâce aux completion callbacks.

  • Je voudrais bien t'aider, mais il fait 37° ici et rien qu'en voyant ces [[]]] mon esprit a pris 10° en plus et provoqué une alerte de surchauffe..

    Quant j'ai un problème du même genre, je crée une mini-application ne faisant que ça, une sorte de bac à sable pour bien isoler le dysfonctionnement. Cela m'aide à me concentrer sur l'essentiel et c'est plus facile à publier sur un forum qu'une poignée de ligne de codes alors que le problème peut venir d'ailleurs.

  • Ben77650Ben77650 Membre
    juillet 2018 modifié #5

    @Joanna Carter ça ne m'a pas posé de souci pour redimensionner mon bouton, ni le replacer.

    @Pyroh j'ai essayé ça mais le résultat est toujours foireux, il fait l'animation pour bien se placer à la nouvelle position, mais à la fin de l'animation le bouton reprends sa place initiale (et le bouton ne change pas sa hauteur)

    [UIView animateWithDuration:2.0 animations:^{
    
        self.firstThemeButton.frame = CGRectMake(self.view.center.x - self.firstThemeButton.frame.size.width / 2,
                                                 self.view.center.y - self.firstThemeButton.frame.size.height / 2,
                                                 self.firstThemeButton.frame.size.width,
                                                 self.firstThemeButton.frame.size.height);
    
        self.titleLabel.alpha = 0;
        self.descLabel.alpha = 0;
        self.separatorView.alpha = 0;
        self.logoImageView.alpha = 0;
        self.arrowImageView.alpha = 0;
    
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
    
            [self.firstThemeButton setTitle:@"" forState:UIControlStateNormal];
    
            self.firstThemeButton.frame = CGRectMake(self.view.center.x - self.firstThemeButton.frame.size.width / 2,
                                                     self.view.center.y - self.firstThemeButton.frame.size.height / 2,
                                                     self.firstThemeButton.frame.size.width,
                                                     self.firstThemeButton.frame.size.height * 2);
    
        } completion:^(BOOL finished) {
        }];
    }];
    

    @Draken c'est mon 1er ViewController et il n'y a que ça dessus, donc ça viens forcément de la et pas d'ailleurs

  • @Ben77650 a dit :
    @Draken c'est mon 1er ViewController et il n'y a que ça dessus, donc ça viens forcément de la et pas d'ailleurs

    Bah non, il n'y a pas que ça. Il manque les contraintes et le Storyboard.

  • Au lieu de jouer avec la frame essaie de manipuler plutôt center et bounds.

  • Joanna CarterJoanna Carter Membre, Modérateur

    Comme dit Draken, avec l'autolayout, il faut jouer avec les contraintes et pas le frame/bounds/width/height/etc.

  • @Joanna Carter a dit :
    Comme dit Draken, avec l'autolayout, il faut jouer avec les contraintes et pas le frame/bounds/width/height/etc.

    Normalement oui mais il dit avoir testé avec et sans. D'où mon scepticisme...

  • Ben, on peut créer des outlets à partir des contraintes pour les animer.

  • Si tu utilises des contraintes, alors anime les contraintes. Change leurs valeurs.
    De plus, il faut que tu mettes [[self view] layoutIfNeeded]; à la fin des différents changements des contraintes.

  • Pour info sur mon bouton j'ai ces contraintes la :

    • Proportional Width to Superview
    • Height Equals 60
    • Align Center X to Safe Area
    • Trailing Space to Arrow Image (une image view) Equals 15
    • Align Center Y to Arrow Image
    • Top Space to Desc Label (un label) Equals 20.

    J'ai supprimer la dernière et ça ne solutionne pas mon souci de placement de bouton :(

  • Joanna CarterJoanna Carter Membre, Modérateur

    Donc, animes les contraintes !

  • Si j'ai bien compris, ton bouton est centré horizontalement par rapport à la superView.
    Ton bouton est aligné en hauteur pour être à la même hauteur (de manière centrée) que le Arrow Image.

    Tu souhaites faire en sorte que ton bouton ailles au centre verticalement de la superView dans la première animation.

    Tu as Align Center Y to Arrow Image, donc clairement, changer sa frame en y ne marchera pas.
    Puisque si c'est bien compris avec self.view.center.y - self.firstThemeButton.frame.size.height / 2,.

    Un truc simple à faire :

    @property (nonatomic, strong) IBOutlet NSLayoutConstraint *firstButtonAlignCenterYToSuperViewConstraint;
    @property (nonatomic, strong) IBOutlet NSLayoutConstraint *firstButtonAlignCenterYArrowConstraint;
    

    Dans Interface Builder :
    Créer la première contrainte (que tu n'as pas déjà créé).
    Lie les 2 IBOutlet.
    Passe la propreté de firstButtonAlignCenterYToSuperViewConstraint à 250. (Low)
    Passe la propreté de firstButtonAlignCenterYArrowConstraint à 750. (High)

    Dans le block d'animation, juste fait :

    firstButtonAlignCenterYToSuperViewConstraint.priority = JeNeSaisPlusQuelNomDeNumHigh;
    firstButtonAlignCenterYArrowConstraint.priority = JeNeSaisPlusQuelNomDeNumLow;
    //Change tes autres alphas
    [[self view] layoutIfNeeded];
    

    Une fois que tu as compris comment faire, créé un IBOutlet pour la contrainte de width du bouton, et tu peux faire un laConstrainte.constant = ??

  • Ben77650Ben77650 Membre
    juillet 2018 modifié #15

    @Larme même en faisant comme ça j'ai le même souci, de vue qui se place à sa position initiale :/

    [UIView animateWithDuration:2.0 animations:^{
    
        [self.firstThemeButton removeConstraint:self.buttonTopCT];
    
        self.firstButtonAlignCenterYToSuperViewConstraint.priority = UILayoutPriorityDefaultHigh;
        self.firstButtonAlignCenterYArrowConstraint.priority = UILayoutPriorityDefaultLow;
    
        self.titleLabel.alpha = 0;
        self.descLabel.alpha = 0;
        self.separatorView.alpha = 0;
        self.logoImageView.alpha = 0;
        self.arrowImageView.alpha = 0;
    
        [[self view] layoutIfNeeded];
    
    }
    
  • Bon ça a marché voila le code mis en place

    [UIView animateWithDuration:2.0 animations:^{
    
        [self.firstThemeButton removeConstraint:self.buttonTopCT];
        [self.firstThemeButton removeConstraint:self.firstButtonAlignCenterYArrowConstraint];
    
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.firstThemeButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
    
        self.titleLabel.alpha = 0;
        self.descLabel.alpha = 0;
        self.separatorView.alpha = 0;
        self.logoImageView.alpha = 0;
        self.arrowImageView.alpha = 0;
    
        [[self view] layoutIfNeeded];
    
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
    
            [self.firstThemeButton setTitle:@"" forState:UIControlStateNormal];
    
            self.heightButtonCT.constant = self.heightButtonCT.constant * 2;
    
            [[self view] layoutIfNeeded];
    
        } completion:^(BOOL finished) {
        }];
    }];
    

    Merci @Joanna Carter @Larme @Pyroh @Draken pour votre aide

  • Il y a un truc curieux dans ton code. Tu détruits DEUX contraintes au début de l'animation, pour n'en reconstruire qu'une seule juste après. C'est normal ?

  • Alors que tu tu les gardes, un activate/deactivate devrait être suffisant...

  • @Draken oui c'est normal, les 2 contraintes sont des contraintes sur des éléments que je passe en alpha 0 donc j'ai plus envie que les contraintes existent entre ces entités.

    @Larme elles ne me sont plus utiles après donc autant les virer, tu crois pas ?

  • @Ben77650 a dit :
    @Draken oui c'est normal, les 2 contraintes sont des contraintes sur des éléments que je passe en alpha 0 donc j'ai plus envie que les contraintes existent entre ces entités.

    C'est risqué ça. Cela pourrais poser problème avec une future version d'iOS, si le moteur de contraintes devient plus .. contraignant exigeant que maintenant ! Par prudence tu devrais aussi désactiver ces entités avec isHidden (pour une réutilisation éventuelle) ou un removeFromSuperView().

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