iOS: comment s'anime avec une nouvelle contrainte de mise en page automatique (hauteur)

123

Je n'ai jamais travaillé avec des contraintes de mise en page automatique auparavant. J'ai une petite nouvelle application sur laquelle je travaille et j'ai remarqué que les vues du NIB par défaut sont mises en page automatiquement. Donc, j'ai pensé que je profiterais de l'occasion pour travailler avec et essayer de comprendre où Apple allait avec cela.

Premier défi:

J'ai besoin de redimensionner un MKMapView et je voudrais l'animer à la nouvelle position. Si je fais cela comme je suis habitué:

[UIView animateWithDuration:1.2f
     animations:^{
         CGRect theFrame = worldView.frame;
         CGRect newFrame = CGRectMake(theFrame.origin.x, theFrame.origin.y, theFrame.size.width, theFrame.size.height - 170);
         worldView.frame = newFrame;
}];

... alors le MKMapView reviendra à sa hauteur d'origine chaque fois qu'une vue sœur est mise à jour (dans mon cas, un titre de UISegmentedControl est mis à jour [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0]).

Alors, ce que je pense que je veux faire est de changer les contraintes du MKMapView d'être égale à la hauteur de la vue parent d'être par rapport au sommet de la UISegmentedControl qu'il était couvrant:V:[MKMapView]-(16)-[UISegmentedControl]

Ce que je veux, c'est que la hauteur de MKMapView soit raccourcie afin que certains contrôles sous la vue de la carte soient révélés. Pour ce faire, je pense que je dois changer la contrainte d'une vue pleine taille fixe à une vue où le bas est contraint au sommet d'un UISegmentedControl ... et j'aimerais qu'il s'anime lorsque la vue se réduit à une nouvelle taille.

Comment s'y prend-on?

Modifier - cette animation ne s'anime pas bien que le bas de la vue monte instantanément de 170:

    [UIView animateWithDuration:1.2f
         animations:^{
             self.nibMapViewConstraint.constant = -170;

    }];

et le nibMapViewConstraintest câblé dans IB à la contrainte d'espace vertical inférieure.

Meltemi
la source
1
Je sais que vous pouvez facilement changer la valeur constante de la contrainte dans un bloc [UIView animateWithDuration ..] pour animer le changement de hauteur. Vous devez créer un IBOutlet pour cette contrainte et le raccorder à votre xib, ou conserver une référence à celui-ci si vous l'avez créé dans le code (ou parcourez toutes les contraintes pour le rechercher). Je ne sais pas comment animer les changements relatedBy, mais j'ai lu que vous ne devriez changer que la constante et non les autres valeurs d'une contrainte (pour les autres valeurs, créez une nouvelle contrainte).
yuf
Hmm. Je pensais pouvoir le faire mais je ne suis pas animée. Il change, avec succès, et se trouve dans le bloc d'animation, mais ne s'anime pas !?!
Meltemi
J'ai trouvé ma réponse ici: < stackoverflow.com/questions/12926566/… >
Meltemi
1
N'oubliez pas la [vue layoutIfNeeded], c'était aussi mon problème haha. C'est la même question qui a résolu mon problème.
yuf

Réponses:

179

Après avoir mis à jour votre contrainte:

[UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}];

Remplacez self.viewpar une référence à la vue contenant.

Ed McManus
la source
4
cela fonctionne pour la vue elle-même, mais les vues qui ont des contraintes sur cette vue se déplacent instantanément. Que fais-je? ty
dietbacon
7
vous devez également appeler layout si nécessaire sur ces vues. Cependant, cela ne fonctionne pas vraiment correctement car cela animera également l'actualisation de la vue. Comment animer l'ajustement de contrainte uniquement dans les autres vues?
ngb
3
Attention: si vous utilisez le, UIViewAnimationOptionBeginFromCurrentStateles contraintes de mise en page seront définies AVANT l'animation!
Robert
12
Au lieu d'appeler layoutIfNeededpour chacune de ces vues, appelez simplement[[self.view superview] layoutIfNeeded];
Flying_Banana
2
@ngb vous devez changer la constante de contrainte à l' intérieur du bloc d'animation. De cette façon, la contrainte change avec l'animation et vous pouvez continuer à utiliser UIViewAnimationOptionBeginFromCurrentState.
Eran Goldin
86

Cela fonctionne pour moi (iOS7 et iOS8 +). Cliquez sur la contrainte de mise en page automatique que vous souhaitez ajuster (dans le générateur d'interface, par exemple la contrainte supérieure). Ensuite, faites-en un IBOutlet;

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

Animer vers le haut;

    self.topConstraint.constant = -100;    
    [self.viewToAnimate setNeedsUpdateConstraints]; 
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded]; 
    }];

Animer le retour au lieu d'origine

    self.topConstraint.constant = 0;    
    [self.viewToAnimate setNeedsUpdateConstraints];  
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded];
    }];
DevC
la source
2
SENSATIONNEL!! Cela fonctionne vraiment vraiment! Cette réponse m'a ouvert les yeux. Merci beaucoup! - Erik
Erik van der Neut
2
@ErikvanderNeut c'était pour moi aussi, heureux que cela ait été utile. Je vais désormais animer les contraintes plutôt que la position des cadres.
DevC
ne manquez pas d'ajouter: [containerView layoutIfNeeded]; Il garantit que toutes les opérations de mise en page en attente ont été effectuées AVANT le bloc animateWithDuration.
ingconti
11

Il existe un très bon tutoriel d'Apple lui-même qui explique comment utiliser l'animation avec la mise en page automatique. Suivez ce lien , puis trouvez la vidéo intitulée "Mise en page automatique par exemple". Elle donne des informations intéressantes sur la mise en page automatique et la dernière partie concerne l'utilisation de l'animation.

Glenn
la source
3

J'ai mis à disposition cette petite démo . Il montre comment les contraintes de mise en page automatique peuvent être modifiées et animées dans un exemple très simple. Jetez simplement un œil à DemoViewController.m .

Jens Schwarzer
la source
1

La plupart des gens utilisent la disposition automatique pour mettre en page des éléments sur leurs vues et modifier les contraintes de disposition pour créer des animations.

Un moyen simple de le faire sans beaucoup de code consiste à créer l'UIView que vous souhaitez animer dans Storyboard, puis à créer un UIView caché à l'endroit où vous souhaitez que l'UIView se termine. Vous pouvez utiliser l'aperçu dans xcode pour vous assurer que les deux UIViews sont là où vous le souhaitez. Après cela, masquez l'UIView de fin et permutez les contraintes de mise en page.

Il existe un podfile pour permuter les contraintes de mise en page appelé SBP si vous ne voulez pas l'écrire vous-même.

Voici un tutoriel .

Arjay Waran
la source
0

Pas besoin d'utiliser plus IBOutlet referencede contrainte au lieu de cela, vous pouvez directement accessou updatedéjà appliquer la contrainte appliquée par Programmaticallyou depuis Interface Buildern'importe quelle vue utilisant la KVConstraintExtensionsMasterbibliothèque. Cette bibliothèque gère également le Cumulativecomportement de NSLayoutConstraint.

Pour ajouter une contrainte de hauteur sur containerView

 CGFloat height = 200;
 [self.containerView applyHeightConstrain:height];

Pour mettre à jour la contrainte de hauteur de containerView avec animation

[self.containerView accessAppliedConstraintByAttribute:NSLayoutAttributeHeight completion:^(NSLayoutConstraint *expectedConstraint){
        if (expectedConstraint) {
            expectedConstraint.constant = 100;

            /* for the animation */ 
            [self.containerView  updateModifyConstraintsWithAnimation:NULL];
      }
    }];
keshav vishwkarma
la source