¿Cómo agregar animation mientras se cambia el modo oculto de una uiview?

Quiero agregar animation a una vista al cambiar su modo oculto, es decir

my_view.hidden=YES; 

Agregué un button en la barra de navigation. Cuando hacemos clic en él, la nueva vista está configurada para mostrarse. Se dibuja en la parte superior de la tabla de navigation.

Lamentablemente, oculto no es una propiedad que se pueda animar a través de animaciones UIView. Creo que tu mejor apuesta puede ser utilizar una de las animaciones que @Erik B sugirió, o comenzar a jugar con Core Animations, que son mucho más poderosas. Eche un vistazo a la documentation de las animaciones UIView y Core Animations.

Logré algo así como lo que sugiere utilizar las animaciones de UIView para deslizar la nueva vista desde debajo de otra vista. Esto hizo que pareciera que se desliza un cajón. Si quieres hacer algo así, necesitas interceptar el evento dentro del retoque y colocar el código de animation allí.

 - (IBAction)buttonClicked:(id)sender { [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationCurveEaseOut animations:^(void) { self.myView.frame = /* set the frame here */ } completion:NULL]; } 

Anime la opacidad de la vista del 100% al 0%. Haga que la callback de finalización de la animation establezca que la vista esté oculta. Es posible que también desee restablecer la opacidad al 100% durante la callback, por lo que la vista se mostrará completamente opaca cuando la muestre.

 yourView.alpha = 0.0 //for zero opacity yourView.alpha = 1.0 //for 100% opacity 

Sin embargo, no hay animation para ocultar; obtienes el mismo resultado con el código Swift a continuación:

 UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: { self.yourView.alpha = 0 // Here you will get the animation you want }, completion: { _ in self.yourView.hidden = true // Here you hide it when animation done }) 

Aquí hay una categoría que escribí para presentar una nueva propiedad "oculta" en UIView que admite correctamente la animation:

 @implementation UIView (AnimateHidden) -(void)setHiddenAnimated:(BOOL)hide { [UIView animateWithDuration:0.5 delay:0.0 options: UIViewAnimationCurveEaseOut animations:^ { [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; if (hide) self.alpha=0; else { self.hidden= NO; self.alpha=1; } } completion:^(BOOL b) { if (hide) self.hidden= YES; } ]; } @end 

Creo que la forma más adecuada de hacerlo es:

 [UIView transitionWithView:aView duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:^(void){ aView.hidden = NO; } completion:nil]; 

Actualizado a Swift 3 :

 UIView.animate(withDuration: 0.2, delay: 0.2, options: .curveEaseOut, animations: {firstView.alpha = 0}, completion: { _ in firstView.isHidden = true //Do anything else that depends on this animation ending }) 

Y si desea animar algo de nuevo después de que la primera vista se haya ido, puede replicar el código dentro del bloque de finalización con alpha = 1 y hidden = false .

Esto se corrige la versión de NJ:

 @implementation UIView (AnimateHidden) -(void)setHiddenAnimated:(BOOL)hide duration:(NSTimeInterval)duration { if(self.hidden == hide) return; if(hide) self.alpha = 1; else { self.alpha = 0; self.hidden = NO; } [UIView animateWithDuration:duration animations:^{ if (hide) self.alpha = 0; else self.alpha = 1; } completion:^(BOOL finished) { if(finished) self.hidden = hide; }]; } @end 

Aquí hay una versión rápida para esto:

  UIView.animateWithDuration(0.5, delay: 0.2, options: UIViewAnimationOptions.CurveEaseOut, animations: { objView.alpha = 0 }, completion: { finished in objView.hidden = true }) 

Esto realiza una animation con una duración de 5 segundos y después de un retraso de 2 segundos.

Las opciones de animation disponibles son:

 CurveEaseInOut, CurveEaseIn, CurveEaseOut, CurveLinear 

Las respuestas de NJ y Stanislav me ayudaron a crear una nueva categoría para esto, que creo que mejora sus respuestas, así que pensé que publicaría lo que se me ocurrió en caso de que ayude a alguien más.

Tenga en count que solo funcionará en iOS4 o posterior, ya que está utilizando bloques.

UIView + AnimateHidden.m

 #import "UIView+AnimateHidden.h" @implementation UIView (AnimateHidden) - (void)setHidden:(BOOL)hidden animated:(BOOL)animated { // If the hidden value is already set, do nothing if (hidden == self.hidden) { return; } // If no animation requested, do the normal setHidden method else if (animated == NO) { [self setHidden:hidden]; return; } else { // Store the view's current alpha value CGFloat origAlpha = self.alpha; // If we're unhiding the view, make it invisible initially if (hidden == NO) { self.alpha = 0; } // Unhide the view so we can see the animation self.hidden = NO; // Do the animation [UIView animateWithDuration:0.5 delay:0.0 options: UIViewAnimationOptionCurveEaseOut animations:^{ // Start animation block if (hidden == YES) { self.alpha = 0; } else { self.alpha = origAlpha; } // End animation block } completion:^(BOOL b){ // Start completion block // Finish up by hiding the view if necessary... self.hidden = hidden; // ... and putting back the correct alpha value self.alpha = origAlpha; // End completion block }]; } } @end 

Dado que algunas de estas respuestas son un poco abarrotadas, pensé que podría publicar mi layout minimalist de esta API. También agregué la demora y la duración, porque no.

En la implementación que tenemos.

 #import "UIView+AnimateHidden.h" @implementation UIView (AnimateHidden) - (void)setHiddenAnimated:(BOOL)hide delay:(NSTimeInterval)delay duration:(NSTimeInterval)duration { [UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionAllowAnimatedContent animations:^{ if (hide) { self.alpha = 0; } else { self.alpha = 0; self.hidden = NO; // We need this to see the animation 0 -> 1 self.alpha = 1; } } completion:^(BOOL finished) { self.hidden = hide; }]; } @end 

En el file de encabezado que tenemos.

 #import <UIKit/UIKit.h> @interface UIView (AnimateHidden) - (void)setHiddenAnimated:(BOOL)hide delay:(NSTimeInterval)delay duration:(NSTimeInterval)duration; @end 

Otra versión si desea utilizar types de animation más complejos o animaciones que no son compatibles con UIView

 - (void)setHidden:(BOOL)hidden withAnimationDuration:(NSTimeInterval)duration { CATransition* transition = ({ CATransition* its = [CATransition animation]; its.duration = duration; its.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut]; its.type = kCATransitionPush; its.subtype = (hidden ? @"fromBottom" : @"fromTop"); its }); UIView* containerView = self.superview; [containerView.layer removeAllAnimations]; [containerView.layer addAnimation: transition forKey: kCATransition]; self.hidden = hidden; if (!hidden) { [self.superview bringSubviewToFront: self]; } } 

Aquí está el código que usé para modelar una vista "creciendo" y "encogiéndose" en un button "mostrar más …" y "mostrar less …". Modelado fuera de la respuesta de Palyancodr

Este enfoque me permite crear ambas vistas en el guión gráfico para que las restricciones funcionen como se espera en los diferentes dispositivos iOS y no necesito personalizar el código de todas las restricciones.

 @IBAction func showMoreOrLessAction(_ sender: Any) { // if small view showing if showMoreLargeView.isHidden { showMoreSmallView.isHidden = true //showMoreLargeView.isHidden = false UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: { self.showMoreLargeView.alpha = 1 // Here you will get the animation you want }, completion: { _ in self.showMoreLargeView.isHidden = false // Here you hide it when animation done }) } else { // large view showing //showMoreSmallView.isHidden = false UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: { self.showMoreSmallView.alpha = 1 // Here you will get the animation you want }, completion: { _ in self.showMoreSmallView.isHidden = false // Here you hide it when animation done }) showMoreLargeView.isHidden = true } }