2012-04-06 22 views
8

Mire this video de la aplicación MLB At Bat. Básicamente, solo quiero presentar un modalViewController con el estilo UIModalPresentationFormSheet y hacer que crezca desde otra vista y luego voltear. Como cuando toca un juego en el marcador de la aplicación MLB. Alguien sabe cómo puedo lograr esto?Voltear, crecer y Traducir animación

Gracias

EDIT: Mi vista principal es más o menos la misma configuración que la aplicación de la MLB. Estoy usando AQGridView y quiero que la animación ocurra cuando se toca una celda en la vista de cuadrícula.

EDIT 2: Yo también estaría abierto a abandonando el concepto UIViewController y simplemente usando una llanura UIView, a continuación, replicar el estilo de UIModalPresentationFormSheet manualmente si eso es más fácil.

EDIT 3: Bien, olvídate de usar un UIViewController para hacer esto, ya que no he recibido ninguna respuesta, asumiré que no es posible. Mi nueva pregunta es ¿cómo puedo replicar la animación en el video publicado usando solo UIView? Entonces, básicamente, la vista inicial necesita crecer, moverse y voltear todo al mismo tiempo.

EDIT 4: Creo que tengo la animación real resuelta, ahora mi único problema es calcular las coordenadas para alimentar en CATransform3DTranslate. Mi vista debe animarse exactamente como en el video. Necesita comenzar sobre otra vista y animar al centro de la pantalla. Así es como estoy tratando de calcular las coordenadas de la vista que aparece en el centro:

CGPoint detailInitialPoint = [gridView convertPoint:view.frame.origin toView:detailView.frame.origin]; 
CGPoint detailFinalPoint = detailView.frame.origin; 

gridView es la vista contenedora de mi vista principal que contiene los elementos de la cuadrícula más pequeños. view es el elemento de cuadrícula específico del que estamos animando. Y detailView es la vista que aparece en el medio de la pantalla.

Respuesta

1

OK, lo descubrí. Esto es lo que hice:

CGFloat duration = 0.8; 

/* 
//Detail View Animations 
*/ 

CATransform3D initialDetailScale = CATransform3DMakeScale(view.frame.size.width/vc.view.frame.size.width, view.frame.size.height/vc.view.frame.size.height, 1.0); 
CATransform3D initialDetailTransform = CATransform3DRotate(initialDetailScale, -M_PI, 0.0, -1.0, 0.0); 
CATransform3D finalDetailScale = CATransform3DMakeScale(1.0, 1.0, 1.0); 
CATransform3D finalDetailTransform = CATransform3DRotate(finalDetailScale, 0.0, 0.0, -1.0, 0.0); 

NSMutableArray *detailAnimations = [NSMutableArray array]; 

CABasicAnimation *detailTransform = [CABasicAnimation animationWithKeyPath:@"transform"]; 
detailTransform.fromValue = [NSValue valueWithCATransform3D:initialDetailTransform]; 
detailTransform.toValue = [NSValue valueWithCATransform3D:finalDetailTransform]; 
detailTransform.duration = duration; 
[detailAnimations addObject:detailTransform]; 

CABasicAnimation *detailFadeIn = [CABasicAnimation animationWithKeyPath:@"opacity"]; 
detailFadeIn.fromValue = [NSNumber numberWithFloat:1.0]; 
detailFadeIn.toValue = [NSNumber numberWithFloat:1.0]; 
detailFadeIn.duration = duration/2; 
detailFadeIn.beginTime = duration/2; 
[detailAnimations addObject:detailFadeIn]; 

CABasicAnimation *detailMove = [CABasicAnimation animationWithKeyPath:@"position"]; 
detailMove.fromValue = [NSValue valueWithCGPoint:vc.view.layer.position]; 
detailMove.toValue = [NSValue valueWithCGPoint:self.view.layer.position]; 
detailMove.duration = duration; 
[detailAnimations addObject:detailMove]; 

CAAnimationGroup *detailGroup = [CAAnimationGroup animation]; 
[detailGroup setAnimations:detailAnimations]; 
[detailGroup setDuration:duration]; 
detailGroup.removedOnCompletion = NO; 
detailGroup.fillMode = kCAFillModeForwards; 
detailGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
[vc.view.layer addAnimation:detailGroup forKey:@"anim"]; 

/* 
//Grid Item View Animations 
*/ 

CATransform3D initialGridScale = CATransform3DMakeScale(1.0, 1.0, 1.0); 
CATransform3D initialGridTransform = CATransform3DRotate(initialGridScale, 0.0, 0.0, 1.0, 0.0); 
CATransform3D finalGridScale = CATransform3DMakeScale(vc.view.frame.size.width/view.frame.size.width, vc.view.frame.size.height/view.frame.size.height, 1.0); 
CATransform3D finalGridTransform = CATransform3DRotate(finalGridScale, M_PI, 0.0, 1.0, 0.0); 

NSMutableArray *gridAnimations = [NSMutableArray array]; 

CABasicAnimation *gridTransform = [CABasicAnimation animationWithKeyPath:@"transform"]; 
gridTransform.fromValue = [NSValue valueWithCATransform3D:initialGridTransform]; 
gridTransform.toValue = [NSValue valueWithCATransform3D:finalGridTransform]; 
gridTransform.duration = duration; 
[gridAnimations addObject:gridTransform]; 

CABasicAnimation *gridFadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"]; 
gridFadeOut.fromValue = [NSNumber numberWithFloat:0.0]; 
gridFadeOut.toValue = [NSNumber numberWithFloat:0.0]; 
gridFadeOut.duration = duration/2; 
gridFadeOut.beginTime = duration/2; 
[gridAnimations addObject:gridFadeOut]; 

CABasicAnimation *gridMove = [CABasicAnimation animationWithKeyPath:@"position"]; 
gridMove.fromValue = [NSValue valueWithCGPoint:view.layer.position]; 
gridMove.toValue = [NSValue valueWithCGPoint:[self.view.layer convertPoint:self.view.layer.position toLayer:gridView.layer]]; 
gridMove.duration = duration; 
[gridAnimations addObject:gridMove]; 

CAAnimationGroup *gridGroup = [CAAnimationGroup animation]; 
[gridGroup setAnimations:gridAnimations]; 
gridGroup.duration = duration; 
gridGroup.fillMode = kCAFillModeForwards; 
gridGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
gridGroup.removedOnCompletion = NO; 
[view.layer addAnimation:gridGroup forKey:@"anim"]; 

que estoy haciendo esto con un elemento en una AQGridView. En mi muestra de código view es la instancia de AQGridViewCell que estoy animando. Y vc.view es mi detalle UIViewController/UIView que estoy mostrando.

+0

Estoy tratando de conseguir esto para trabajar para una aplicación de iPhone. ¿Qué hiciste con la vista detallada antes de ejecutar este código? ¿Agregaste la vista del controlador de vista detallada a la jerarquía? Si es así, ¿qué marco fue establecido? Actualmente, cuando ejecuto este código obtengo la mitad de la vista de la cuadrícula, pero no aparece nada para la vista de detalles. – hundreth

+0

@hundreth Agregué la vista de detalles como una subvista de la vista de cuadrícula y la centré. – edc1591

6

Puede implementar su propia transición usando una categoría en UIViewControler.

UIViewController + ShowModalFromView.h

#import <Foundation/Foundation.h> 
#import <QuartzCore/QuartzCore.h> 

@interface UIViewController (ShowModalFromView) 
- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view; 
@end 

UIViewController + ShowModalFromView.m

#import "UIViewController+ShowModalFromView.h" 

@implementation UIViewController (ShowModalFromView) 

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view { 
    modalViewController.modalPresentationStyle = UIModalPresentationFormSheet; 

// Add the modal viewController but don't animate it. We will handle the animation manually 
[self presentModalViewController:modalViewController animated:NO]; 

// Remove the shadow. It causes weird artifacts while animating the view. 
CGColorRef originalShadowColor = modalViewController.view.superview.layer.shadowColor; 
modalViewController.view.superview.layer.shadowColor = [[UIColor clearColor] CGColor]; 

// Save the original size of the viewController's view  
CGRect originalFrame = modalViewController.view.superview.frame; 

// Set the frame to the one of the view we want to animate from 
modalViewController.view.superview.frame = view.frame; 

// Begin animation 
[UIView animateWithDuration:1.0f 
       animations:^{ 
        // Set the original frame back 
        modalViewController.view.superview.frame = originalFrame; 
       } 
       completion:^(BOOL finished) { 
        // Set the original shadow color back after the animation has finished 
        modalViewController.view.superview.layer.shadowColor = originalShadowColor; 
       }]; 
} 

@end 

Esto se puede cambiar fácilmente a usar cualquier transición animada desea; para el tuyo, es posible que desees utilizar un CA3DTransform. ¡Espero que esto ayude!

+0

¿Dónde hago mis animaciones personalizadas? ¿Sustituyo las animaciones de bloque 'UIView' con animaciones de CoreAnimation? – edc1591

+0

Sí, reemplace las animaciones simples de UIView con animaciones más complejas. Aunque no estoy seguro si la sombra hace cosas raras con CoreAnimation. Debería ser fácil probarlo de cualquier manera. – sgonzalez

+0

Puedo hacer que la animación personalizada funcione de la manera que la tiene, pero no puedo encontrar la manera de combinar esto con una tapa utilizando el método aquí para lograr la vuelta http://stackoverflow.com/a/7463047/639668 – edc1591

1

para hacer un flip, crecer y traducen la animación se puede utilizar el siguiente código:

- (void)animate { 
    int newX, newY; //New position 
    int newW, newH; //New size 
    [UIView animateWithDuration:someDuration delay:someDelay animations:^{ 
     yourView.transform = CATransform3DMakeRotation(M_PI_2,1.0,0.0,0.0); //flip halfway 
     yourView.frame = CGRectMake(newX/2, newY/2, newW/2, newH/2); 
    } completion:^{ 
     while ([yourView.subviews count] > 0) 
      [[yourView.subviews lastObject] removeFromSuperview]; // remove all subviews 
     // Add your new views here 
     [UIView animateWithDuration:someDuration delay:someDelay animations:^{ 
      yourView.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0); //finish the flip 
      yourView.frame = CGRectMake(newX, newY, newW, newH); 
     } completion:^{ 
      // Flip completion code here 
     }]; 
    }]; 
} 

Espero que esto ayude!

+1

Tenía la esperanza de hacer esto usando 'transform' y no' frame' para que mis vistas no estén distorsionadas. – edc1591

+0

Sé cómo construir las transformaciones, pero no puedo averiguar cómo calcular la posición correcta para la capa. – edc1591

+0

Creo que puedes hacer 'transform' pura usando' CGAffineTransformConcat() 'como aquí http://stackoverflow.com/questions/1111277/applying-multiple-transforms-to-a-uiview-calayer ¿Dónde quieres que aparezca la vista? ¿para ser mostrado? – sgonzalez

0

Recomiendo echar un vistazo a la publicación this.

No debería necesitar manejar realmente toda esta animación usted mismo.

Si se utiliza el método UIView clase transitionFromView:toView:duration:options:completion: y pasando UIViewAnimationOptionTransitionFlipFromLeft o UIViewAnimationOptionTransitionFlipFromRight - mire como se desea que la animación para voltear.

He implementado lo mismo que se muestra en la aplicación MLB utilizando este método. Su from view sería la celda en la cuadrícula y to view sería lo que haría en la "parte posterior" de la celda.

Espero que esto reduzca el código general que necesitará.

+0

Estoy intentando algo similar y estoy luchando. ¿Cómo escalaste y moviste la vista a su posición mientras estaba volteando? – kyleplattner

+0

Ha pasado un tiempo desde que miré esto, pero creo que dependerá de los marcos de las vistas 'fromView' y' toView' que pases al método 'transitionFromView: toView: duration: options: completion:'. – njkremer

0

Usaría UICollectionView con un UICollectionViewCell personalizado y animaré con su llamada de delegado ... Solo un ejemplo para que otros elijan.

#pragma mark - UICollectionViewDelegate 
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: 
(NSIndexPath *)indexPath 
{ 


[UIView beginAnimations:@"showImage" context:Nil]; 
    CGRect cellFrame = cell.frame; 
    CGRect imgFram = cell.imageView.frame; 
    [UIView setAnimationDuration:0.8]; 
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:cell 
cache:YES]; 
    cellFrame.size = CGSizeMake(200, 200); 
    cellFrame.origin.y = 10; 
    cellFrame.origin.x = 45; 
    cell.frame = cellFrame; 
    imgFram.size = CGSizeMake(200, 200); 
    cell.imageView.frame = imgFram; 
    [collectionView bringSubviewToFront:cell]; 
    [UIView commitAnimations]; 
}