¿Cómo puedo implementar una animación deslizante / deslizante entre las vistas?

Tengo algunas vistas entre las que quiero deslizarme en un progtwig de iOS. En este momento, estoy deslizando entre ellos usando un estilo modal, con una animación de disolver cruzada. Sin embargo, quiero tener una animación deslizante / deslizante como la que ve en la pantalla de inicio y tal. No tengo idea de cómo codificar dicha transición, y el estilo de animación no es un estilo de transición modal disponible. ¿Alguien puede darme un ejemplo del código? No es necesario que sea un modelo modal ni nada, solo encontré el más fácil.

Desde iOS 7, si desea animar la transición entre dos controladores de vista, usaría transiciones personalizadas, como se explica en Transiciones personalizadas de video WWDC 2013 con Controladores de vista . Por ejemplo, para personalizar la presentación de un nuevo controlador de vista, usted debería:

  1. El controlador de vista de destino especificaría self.modalPresentationStyle y transitioningDelegate para la animación de presentación:

     - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { self.modalPresentationStyle = UIModalPresentationCustom; self.transitioningDelegate = self; } return self; } 
  2. Este delegado (en este ejemplo, el controlador de vista en sí) se conformaría a UIViewControllerTransitioningDelegate e implementaría:

     - (id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { return [[PresentAnimator alloc] init]; } // in iOS 8 and later, you'd also specify a presentation controller - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source { return [[PresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting]; } 
  3. Implementarías un animador que realizaría la animación deseada:

     @interface PresentAnimator : NSObject  @end @implementation PresentAnimator - (NSTimeInterval)transitionDuration:(id )transitionContext { return 0.5; } // do whatever animation you want below - (void)animateTransition:(id)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [[transitionContext containerView] addSubview:toViewController.view]; CGFloat width = fromViewController.view.frame.size.width; CGRect originalFrame = fromViewController.view.frame; CGRect rightFrame = originalFrame; rightFrame.origin.x += width; CGRect leftFrame = originalFrame; leftFrame.origin.x -= width / 2.0; toViewController.view.frame = rightFrame; toViewController.view.layer.shadowColor = [[UIColor blackColor] CGColor]; toViewController.view.layer.shadowRadius = 10.0; toViewController.view.layer.shadowOpacity = 0.5; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromViewController.view.frame = leftFrame; toViewController.view.frame = originalFrame; toViewController.view.layer.shadowOpacity = 0.5; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end 
  4. También implementaría un controlador de presentación que se ocuparía de limpiar la jerarquía de vista por usted. En este caso, dado que estamos superponiendo completamente la vista de presentación, podemos eliminarla de la jerarquía cuando finalice la transición:

     @interface PresentationController: UIPresentationController @end @implementation PresentationController - (BOOL)shouldRemovePresentersView { return true; } @end 
  5. Opcionalmente, si desea que este gesto sea interactivo, también deberá:

    • Cree un controlador de interacción (por lo general, una UIPercentDrivenInteractiveTransition );

    • Haga que su UIViewControllerAnimatedTransitioning también implemente interactionControllerForPresentation , lo que obviamente devolvería el controlador de interacción antes mencionado;

    • Haga un gesto (o lo que sea) que actualice la interactionController

Todo esto se describe en las transiciones personalizadas antes mencionadas que utilizan controladores de vista .

Por ejemplo, para personalizar la función push / pop del controlador de navegación , consulte Animación de transición personalizada del controlador de navegación.


A continuación, encontrará una copia de mi respuesta original, anterior a las transiciones personalizadas.


La respuesta de @sooper es correcta, que CATransition puede producir el efecto que estás buscando.

Pero, por cierto, si su fondo no es blanco, el kCATransitionPush de CATransition tiene un extraño fundido de entrada y salida al final de la transición que puede ser una distracción (cuando se navega entre imágenes, especialmente, le da un ligero parpadeo efecto). Si sufres de esto, creo que esta simple transición es muy elegante: puedes preparar tu “siguiente vista” para estar justo fuera de la pantalla hacia la derecha, y luego animar el movimiento de la vista actual fuera de la pantalla mientras simultáneamente animar la siguiente vista para mover a donde estaba la vista actual. Tenga en cuenta que, en mis ejemplos, estoy animando subvistas dentro y fuera de la vista principal dentro de un único controlador de vista, pero probablemente tenga la idea:

 float width = self.view.frame.size.width; float height = self.view.frame.size.height; // my nextView hasn't been added to the main view yet, so set the frame to be off-screen [nextView setFrame:CGRectMake(width, 0.0, width, height)]; // then add it to the main view [self.view addSubview:nextView]; // now animate moving the current view off to the left while the next view is moved into place [UIView animateWithDuration:0.33f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{ [nextView setFrame:currView.frame]; [currView setFrame:CGRectMake(-width, 0.0, width, height)]; } completion:^(BOOL finished){ // do whatever post processing you want (such as resetting what is "current" and what is "next") }]; 

Claramente, tendrías que modificar esto para saber cómo tienes todos tus controles configurados, pero esto produce una transición muy simple, sin desvanecimientos ni nada de eso, solo una transición suave y agradable.

Una advertencia: primero, ni este ejemplo, ni el ejemplo de CATransition , son como la animación de la pantalla de inicio de SpringBoard (de la que hablaste), que es continua (es decir, si estás a medio camino, puedes parar y regresar o lo que sea). Estas transiciones son las que una vez para iniciarlas, simplemente suceden. Si necesita esa interacción en tiempo real, eso también se puede hacer, pero es diferente.

Actualizar:

Si desea utilizar un gesto continuo que UIPanGestureRecognizer el dedo del usuario, puede usar UIPanGestureRecognizer lugar de UISwipeGestureRecognizer , y creo que animateWithDuration es mejor que CATransition en ese caso. handlePanGesture mi handlePanGesture para cambiar las coordenadas del frame de coordenadas con el gesto del usuario, y luego modifiqué el código anterior para completar la animación cuando el usuario la soltó. Funciona bastante bien No creo que puedas hacer eso con CATransition muy fácilmente.

Por ejemplo, puede crear un controlador de gestos en la vista principal del controlador:

 [self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]]; 

Y el controlador podría verse así:

 - (void)handlePan:(UIPanGestureRecognizer *)gesture { // transform the three views by the amount of the x translation CGPoint translate = [gesture translationInView:gesture.view]; translate.y = 0.0; // I'm just doing horizontal scrolling prevView.frame = [self frameForPreviousViewWithTranslate:translate]; currView.frame = [self frameForCurrentViewWithTranslate:translate]; nextView.frame = [self frameForNextViewWithTranslate:translate]; // if we're done with gesture, animate frames to new locations if (gesture.state == UIGestureRecognizerStateCancelled || gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateFailed) { // figure out if we've moved (or flicked) more than 50% the way across CGPoint velocity = [gesture velocityInView:gesture.view]; if (translate.x > 0.0 && (translate.x + velocity.x * 0.25) > (gesture.view.bounds.size.width / 2.0) && prevView) { // moving right (and/or flicked right) [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ prevView.frame = [self frameForCurrentViewWithTranslate:CGPointZero]; currView.frame = [self frameForNextViewWithTranslate:CGPointZero]; } completion:^(BOOL finished) { // do whatever you want upon completion to reflect that everything has slid to the right // this redefines "next" to be the old "current", // "current" to be the old "previous", and recycles // the old "next" to be the new "previous" (you'd presumbly. // want to update the content for the new "previous" to reflect whatever should be there UIView *tempView = nextView; nextView = currView; currView = prevView; prevView = tempView; prevView.frame = [self frameForPreviousViewWithTranslate:CGPointZero]; }]; } else if (translate.x < 0.0 && (translate.x + velocity.x * 0.25) < -(gesture.view.frame.size.width / 2.0) && nextView) { // moving left (and/or flicked left) [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ nextView.frame = [self frameForCurrentViewWithTranslate:CGPointZero]; currView.frame = [self frameForPreviousViewWithTranslate:CGPointZero]; } completion:^(BOOL finished) { // do whatever you want upon completion to reflect that everything has slid to the left // this redefines "previous" to be the old "current", // "current" to be the old "next", and recycles // the old "previous" to be the new "next". (You'd presumably. // want to update the content for the new "next" to reflect whatever should be there UIView *tempView = prevView; prevView = currView; currView = nextView; nextView = tempView; nextView.frame = [self frameForNextViewWithTranslate:CGPointZero]; }]; } else { // return to original location [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ prevView.frame = [self frameForPreviousViewWithTranslate:CGPointZero]; currView.frame = [self frameForCurrentViewWithTranslate:CGPointZero]; nextView.frame = [self frameForNextViewWithTranslate:CGPointZero]; } completion:NULL]; } } } 

Utiliza estos métodos de frame simples que supuestamente definirías para tu UX deseado:

 - (CGRect)frameForPreviousViewWithTranslate:(CGPoint)translate { return CGRectMake(-self.view.bounds.size.width + translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height); } - (CGRect)frameForCurrentViewWithTranslate:(CGPoint)translate { return CGRectMake(translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height); } - (CGRect)frameForNextViewWithTranslate:(CGPoint)translate { return CGRectMake(self.view.bounds.size.width + translate.x, translate.y, self.view.bounds.size.width, self.view.bounds.size.height); } 

Su implementación particular indudablemente variará, pero espero que esto ilustre la idea.

Habiendo ilustrado todo esto (complementando y aclarando esta vieja respuesta), debo señalar que ya no uso esta técnica. Hoy en día, generalmente utilizo UIScrollView (con "paging" activado) o (en iOS 6) un UIPageViewController . Esto lo saca del negocio de escribir este tipo de manejador de gestos (y disfruta de una funcionalidad adicional como barras de desplazamiento, rebote, etc.). En la implementación de UIScrollView , simplemente respondo al evento scrollViewDidScroll para asegurarme de que estoy cargando la subvista necesaria.

Podrías crear una animación CATransition . Aquí hay un ejemplo de cómo puede deslizar una segunda vista (desde la izquierda) a la pantalla mientras empuja la vista actual hacia afuera:

 UIView *theParentView = [self.view superview]; CATransition *animation = [CATransition animation]; [animation setDuration:0.3]; [animation setType:kCATransitionPush]; [animation setSubtype:kCATransitionFromLeft]; [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; [theParentView addSubview:yourSecondViewController.view]; [self.view removeFromSuperview]; [[theParentView layer] addAnimation:animation forKey:@"showSecondViewController"]; 

Si desea el mismo efecto de deslizamiento / deslizamiento de página que tiene el trampolín al cambiar de página, ¿por qué no simplemente usar un UIScrollView ?

 CGFloat width = 320; CGFloat height = 400; NSInteger pages = 3; UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,width,height)]; scrollView.contentSize = CGSizeMake(width*pages, height); scrollView.pagingEnabled = YES; 

Y luego usa UIPageControl para obtener estos puntos. 🙂

    Intereting Posts