Je mets à jour une ancienne application avec un AdBannerView
et quand il n'y a pas d'annonce, elle glisse hors écran. Lorsqu'une annonce est diffusée, elle glisse sur l'écran. Trucs de base.
À l'ancienne, j'ai mis le cadre dans un bloc d'animation. Nouveau style, j'ai une IBOutlet
contrainte de mise en page automatique qui détermine la Y
position, dans ce cas, c'est la distance par rapport au bas de la vue d'ensemble et modifie la constante:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
Et la bannière bouge, exactement comme prévu, mais pas d' animation.
MISE À JOUR: J'ai revu la WWDC 12 parler des meilleures pratiques pour maîtriser la mise en page automatique qui couvre l'animation. Il explique comment mettre à jour les contraintes à l'aide de CoreAnimation :
J'ai essayé avec le code suivant, mais obtenez exactement les mêmes résultats:
- (void)moveBannerOffScreen {
_addBannerDistanceFromBottomConstraint.constant = -32;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
_addBannerDistanceFromBottomConstraint.constant = 0;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = TRUE;
}
Sur une note latérale, j'ai vérifié plusieurs fois et cela est en cours d'exécution sur le thread principal .
Réponses:
Deux notes importantes:
Vous devez appeler
layoutIfNeeded
dans le bloc d'animation. Apple vous recommande en fait de l'appeler une fois avant le bloc d'animation pour vous assurer que toutes les opérations de mise en page en attente ont été terminéesVous devez l'appeler spécifiquement sur la vue parent (par exemple
self.view
), pas sur la vue enfant qui a les contraintes qui lui sont attachées. Cela mettra à jour toutes les vues contraintes, y compris l'animation d'autres vues qui pourraient être limitées à la vue dont vous avez modifié la contrainte (par exemple, la vue B est attachée au bas de la vue A et vous venez de changer le décalage supérieur de la vue A et vous voulez la vue B animer avec)Essaye ça:
Objectif c
Swift 3
la source
setNeedsLayout
place delayoutIfNeeded
. Je suis légèrement horrifié par le nombre d'heures que j'ai passées sans remarquer que je viens de taper le mauvais nom de méthode.J'apprécie la réponse fournie, mais je pense que ce serait bien d'aller un peu plus loin.
L'animation de bloc de base de la documentation
mais c'est vraiment un scénario très simpliste. Et si je veux animer des contraintes de sous-vue via le
updateConstraints
méthode?Un bloc d'animation qui appelle la méthode subviews updateConstraints
La méthode updateConstraints est substituée dans la sous-classe UIView et doit appeler super à la fin de la méthode.
Le guide AutoLayout laisse beaucoup à désirer, mais il vaut la peine d'être lu. Je l'utilise moi-même dans le cadre d'un
UISwitch
qui bascule une sous-vue avec une paire deUITextField
s avec une animation d'effondrement simple et subtile (0,2 seconde). Les contraintes de la sous-vue sont gérées dans les méthodes updateConstraints des sous-classes UIView comme décrit ci-dessus.la source
self.view
(et non sur une sous-vue de cette vue), l'appelupdateConstraintsIfNeeded
n'est pas nécessaire (carsetNeedsLayout
il déclenche égalementupdateConstraints
cette vue). Cela pourrait être trivial pour la plupart, mais ce n'était pas pour moi jusqu'à présent;)Généralement, il vous suffit de mettre à jour les contraintes et d'appeler
layoutIfNeeded
à l'intérieur du bloc d'animation. Cela peut être soit en changeant la.constant
propriété d'unNSLayoutConstraint
, en ajoutant des contraintes de suppression (iOS 7), soit en changeant la.active
propriété des contraintes (iOS 8 et 9).Exemple de code:
Exemple de configuration:
Controverse
Il y a des questions à savoir si la contrainte doit être modifiée avant le bloc d'animation, ou à l' intérieur (voir les réponses précédentes).
Ce qui suit est une conversation Twitter entre Martin Pilkington qui enseigne iOS et Ken Ferry qui a écrit Auto Layout. Ken explique que même si la modification des constantes en dehors du bloc d'animation peut actuellement fonctionner, ce n'est pas sûr et elles devraient vraiment être modifiées à l' intérieur du bloc d'animation. https://twitter.com/kongtomorrow/status/440627401018466305
Animation:
Exemple de projet
Voici un projet simple montrant comment une vue peut être animée. Il utilise l'objectif C et anime la vue en modifiant la
.active
propriété de plusieurs contraintes. https://github.com/shepting/SampleAutoLayoutAnimationla source
la source
Solution Swift 4
UIView.animate
Trois étapes simples:
Modifiez les contraintes, par exemple:
Dites au
view
conteneur que sa disposition est sale et que la mise en page automatique doit recalculer la disposition:Dans le bloc d'animation, dites à la disposition de recalculer la disposition, ce qui équivaut à définir directement les images (dans ce cas, la mise en page automatique définira les images):
Exemple le plus simple et complet:
Sidenote
Il y a une 0ème étape facultative - avant de modifier les contraintes que vous voudrez peut-être appeler
self.view.layoutIfNeeded()
pour vous assurer que le point de départ de l'animation provient de l'état avec les anciennes contraintes appliquées (au cas où il y aurait d'autres changements de contraintes qui ne devraient pas être inclus dans l'animation) ):UIViewPropertyAnimator
Comme avec iOS 10, nous avons un nouveau mécanisme d'animation -
UIViewPropertyAnimator
, nous devons savoir que le même mécanisme s'applique essentiellement à lui. Les étapes sont fondamentalement les mêmes:Puisqu'il
animator
s'agit d'une encapsulation de l'animation, nous pouvons garder une référence à elle et l'appeler plus tard. Cependant, comme dans le bloc d'animation, nous disons simplement à la mise en page automatique de recalculer les images, nous devons changer les contraintes avant d'appelerstartAnimation
. Par conséquent, quelque chose comme ça est possible:L'ordre de modification des contraintes et de démarrage d'un animateur est important - si nous modifions simplement les contraintes et laissons notre animateur pour un point ultérieur, le prochain cycle de rafraîchissement peut invoquer le recalcul de la mise en page automatique et le changement ne sera pas animé.
Rappelez-vous également qu'un seul animateur n'est pas réutilisable - une fois que vous l'exécutez, vous ne pouvez pas le "réexécuter". Donc je suppose qu'il n'y a pas vraiment de bonne raison de garder l'animateur, sauf si nous l'utilisons pour contrôler une animation interactive.
la source
Storyboard, Code, Astuces et quelques Gotchas
Les autres réponses sont très bien mais celle-ci met en évidence quelques accrochages assez importants de contraintes d'animation en utilisant un exemple récent. J'ai subi beaucoup de variations avant de réaliser ce qui suit:
Créez les contraintes que vous souhaitez cibler dans les variables de classe pour conserver une référence forte. Dans Swift, j'ai utilisé des variables paresseuses:
Après une certaine expérimentation, j'ai noté que l'on DOIT obtenir la contrainte de la vue AU-DESSUS (alias la superview) les deux vues où la contrainte est définie. Dans l'exemple ci-dessous (MNGStarRating et UIWebView sont les deux types d'éléments entre lesquels je crée une contrainte, et ce sont des sous-vues dans self.view).
Chaînage de filtres
Je profite de la méthode de filtrage de Swift pour séparer la contrainte souhaitée qui servira de point d'inflexion. On pourrait aussi devenir beaucoup plus compliqué, mais le filtre fait du bon travail ici.
Animation des contraintes à l'aide de Swift
En supposant que vous créez une propriété pour filtrer avec des critères précis et atteindre un point d'inflexion spécifique pour votre animation (bien sûr, vous pouvez également filtrer pour un tableau et boucler si vous avez besoin de plusieurs contraintes):
....
Un peu plus tard...
Les nombreux mauvais virages
Ces notes sont vraiment un ensemble de conseils que j'ai écrits pour moi. J'ai fait tous les trucs personnellement et douloureusement. J'espère que ce guide pourra en épargner d'autres.
Attention à zPositioning. Parfois, lorsque rien ne se passe, vous devez masquer certaines des autres vues ou utiliser le débogueur de vues pour localiser votre vue animée. J'ai même trouvé des cas où un attribut d'exécution défini par l'utilisateur a été perdu dans le xml d'un storyboard et a conduit à la vue animée couverte (pendant le travail).
Prenez toujours une minute pour lire la documentation (nouvelle et ancienne), l'aide rapide et les en-têtes. Apple continue d'apporter de nombreuses modifications pour mieux gérer les contraintes de mise en page automatique (voir les vues de pile). Ou au moins le livre de recettes AutoLayout . Gardez à l'esprit que les meilleures solutions se trouvent parfois dans les anciennes documentations / vidéos.
Jouez avec les valeurs de l'animation et envisagez d'utiliser d'autres variantes animateWithDuration.
Ne codez pas en dur des valeurs de mise en page spécifiques comme critères pour déterminer les modifications apportées à d'autres constantes, utilisez plutôt des valeurs qui vous permettent de déterminer l'emplacement de la vue.
CGRectContainsRect
est un exemplelet viewMargins = self.webview.layoutMarginsGuide
: c'est l'exempleExemple rapide de solutions à éviter lors de l'utilisation de story-boards
Si vous oubliez l'un de ces conseils ou les plus simples tels que l'endroit où ajouter le layoutIfNeeded, rien ne se produira probablement: dans ce cas, vous pouvez avoir une solution à moitié cuite comme celle-ci:
Extrait du guide AutoLayout (notez que le deuxième extrait est pour utiliser OS X). BTW - Ce n'est plus dans le guide actuel pour autant que je puisse voir. Les techniques privilégiées continuent d'évoluer.
Animation des modifications apportées par la mise en page automatique
Si vous avez besoin d'un contrôle total sur l'animation des modifications apportées par la mise en page automatique, vous devez effectuer vos modifications de contrainte par programme. Le concept de base est le même pour iOS et OS X, mais il existe quelques différences mineures.
Dans une application iOS, votre code ressemblerait à ceci:
Sous OS X, utilisez le code suivant lorsque vous utilisez des animations basées sur des couches:
Lorsque vous n'utilisez pas d'animations basées sur des calques, vous devez animer la constante à l'aide de l'animateur de la contrainte:
Pour ceux qui apprennent mieux, regardez visuellement cette première vidéo d'Apple .
Porter une attention particulière
Souvent, dans la documentation, il y a de petites notes ou des morceaux de code qui mènent à de plus grandes idées. Par exemple, attacher des contraintes de disposition automatique à des animateurs dynamiques est une grande idée.
Bonne chance et que la force soit avec toi.la source
Solution rapide:
la source
Solution de travail 100% Swift 3.1
j'ai lu toutes les réponses et je veux partager le code et la hiérarchie des lignes que j'ai utilisées dans toutes mes applications pour les animer correctement, Certaines solutions ici ne fonctionnent pas, vous devriez les vérifier sur des appareils plus lents, par exemple l'iPhone 5 en ce moment.
la source
J'essayais d'animer des Contraintes et ce n'était pas vraiment facile de trouver une bonne explication.
Ce que disent les autres réponses est totalement vrai: vous devez appeler à l'
[self.view layoutIfNeeded];
intérieuranimateWithDuration: animations:
. Cependant, l'autre point important est d'avoir des pointeurs pour toutNSLayoutConstraint
ce que vous souhaitez animer.J'ai créé un exemple dans GitHub .
la source
Solution fonctionnelle et juste testée pour Swift 3 avec Xcode 8.3.3:
Gardez juste à l'esprit que self.calendarViewHeight est une contrainte référencée à un customView (CalendarView). J'ai appelé le .layoutIfNeeded () sur self.view et NON sur self.calendarView
J'espère que cette aide.
la source
Il y a un article à ce sujet: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
Dans lequel, il a codé comme ceci:
J'espère que cela aide.
la source
Dans le contexte de l'animation de contraintes, je voudrais mentionner une situation spécifique où j'ai animé une contrainte immédiatement dans une notification keyboard_opened.
La contrainte a défini un espace supérieur depuis un champ de texte jusqu'au sommet du conteneur. À l'ouverture du clavier, je divise simplement la constante par 2.
Je n'ai pas pu réaliser une animation de contrainte lisse cohérente directement dans la notification du clavier. Environ la moitié du temps d'affichage passerait simplement à sa nouvelle position - sans animation.
Il m'est apparu qu'il pourrait y avoir une mise en page supplémentaire suite à l'ouverture du clavier. L'ajout d'un simple bloc dispatch_after avec un délai de 10 ms a rendu l'animation exécutée à chaque fois - sans saut.
la source