¿Cómo animo los cambios de restricciones?
Estoy actualizando una aplicación antigua con un anuncio AdBannerView
y cuando no hay ningún anuncio, se desliza fuera de la pantalla. Cuando hay un anuncio se desliza en la pantalla. Cosas básicas.
Al estilo antiguo, configuro el marco en un bloque de animación. Nuevo estilo, tengo una IBOutlet
restricción de diseño automático que determina la Y
posición, en este caso es la distancia desde la parte inferior de la supervista, y modifico la constante:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
Y el banner se mueve exactamente como se esperaba, pero sin animación.
ACTUALIZACIÓN: Volví a ver la charla de la WWDC 12 sobre Mejores prácticas para dominar el diseño automático , que cubre la animación. Se analiza cómo actualizar restricciones usando CoreAnimation :
Lo intenté con el siguiente código, pero obtuve exactamente los mismos resultados:
- (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;
}
Como nota al margen, lo he comprobado numerosas veces y esto se está ejecutando en el hilo principal .
Dos notas importantes:
Debes llamar
layoutIfNeeded
dentro del bloque de animación. De hecho, Apple recomienda llamarlo una vez antes del bloque de animación para asegurarse de que se hayan completado todas las operaciones de diseño pendientes.Debe llamarlo específicamente en la vista principal (por ejemplo
self.view
), no en la vista secundaria que tiene las restricciones adjuntas. Al hacerlo, se actualizarán todas las vistas restringidas, incluida la animación de otras vistas que podrían estar restringidas a la vista cuya restricción cambió (por ejemplo, la Vista B está adjunta a la parte inferior de la Vista A y usted acaba de cambiar el desplazamiento superior de la Vista A y desea que la Vista B animar con él)
Prueba esto:
C objetivo
- (void)moveBannerOffScreen {
[self.view layoutIfNeeded];
[UIView animateWithDuration:5
animations:^{
self._addBannerDistanceFromBottomConstraint.constant = -32;
[self.view layoutIfNeeded]; // Called on parent view
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[self.view layoutIfNeeded];
[UIView animateWithDuration:5
animations:^{
self._addBannerDistanceFromBottomConstraint.constant = 0;
[self.view layoutIfNeeded]; // Called on parent view
}];
bannerIsVisible = TRUE;
}
veloz 3
UIView.animate(withDuration: 5) {
self._addBannerDistanceFromBottomConstraint.constant = 0
self.view.layoutIfNeeded()
}
Agradezco la respuesta proporcionada, pero creo que sería bueno ir un poco más allá.
La animación de bloque básica de la documentación.
[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
// Make all constraint changes here
[containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];
pero en realidad este es un escenario muy simplista. ¿Qué pasa si quiero animar restricciones de subvista mediante el updateConstraints
método?
Un bloque de animación que llama al método updateConstraints de subvistas.
[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
[self.view layoutIfNeeded];
} completion:nil];
El método updateConstraints se anula en la subclase UIView y debe llamar a super al final del método.
- (void)updateConstraints
{
// Update some constraints
[super updateConstraints];
}
La Guía de AutoLayout deja mucho que desear pero vale la pena leerla. Yo mismo estoy usando esto como parte de una UISwitch
que alterna una subvista con un par de UITextField
s con una animación de colapso simple y sutil (0,2 segundos de duración). Las restricciones para la subvista se manejan en los métodos updateConstraints de las subclases de UIView como se describe anteriormente.