翻转、增长和平移动画

8
看看这个MLB At Bat应用程序的视频。基本上,我想展示一个modalViewController,使用UIModalPresentationFormSheet样式,并从另一个视图中增长然后翻转。就像在MLB应用程序的记分牌上点击游戏时一样。有人知道我怎么做到这一点吗?
谢谢
编辑:我的主视图与MLB应用程序的设置基本相同。我正在使用AQGridView,并希望在单元格在网格视图中被点击时发生动画。
编辑2:如果更容易,我也可以放弃UIViewController的概念,只使用普通的UIView,然后手动复制UIModalPresentationFormSheet的样式。
编辑3:好的,忘记使用UIViewController来完成这个任务,因为我没有得到任何回应,我会认为这是不可能的。我的新问题是如何使用UIView完全复制发布的视频中的动画?所以基本上,初始视图需要同时增长、移动和翻转。
编辑4:我想我已经想出了实际的动画,现在我的唯一问题是计算坐标以输入CATransform3DTranslate。我的视图需要几乎完全像视频中那样进行动画。它需要从另一个视图开始,然后动画到屏幕的中心。这是我正在尝试计算弹出在中心的视图的坐标的方法:
CGPoint detailInitialPoint = [gridView convertPoint:view.frame.origin toView:detailView.frame.origin];
CGPoint detailFinalPoint = detailView.frame.origin;

gridView 是我的主视图的容器视图,它包含了较小的网格项。view 是我们要进行动画处理的具体网格项。而detailView 则是出现在屏幕中央的视图。

5个回答

6
您可以使用UIViewController的类别来实现自己的转换。
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

这可以很容易地更改为使用任何您想要的动画过渡效果;对于您的需求,您可能希望使用CA3DTransform。希望这可以帮到您!


我应该在哪里执行自定义动画?我是否应该用核心动画替换UIView的块动画? - edc1591
是的,用更复杂的动画替换简单的UIView动画。虽然我不确定阴影是否会对核心动画产生奇怪的影响,但无论如何都应该很容易测试。 - sgonzalez
我可以按照您的方式使自定义动画正常工作,但我无法弄清楚如何将其与翻转结合起来,以使用此处的方法实现翻转https://dev59.com/_1TTa4cB1Zd3GeqPvMDl#7463047。 - edc1591
你可以使用相同的方法返回3D变换,并复制其余代码以作用于viewController.view.layer而不是view2.layer。 - sgonzalez

1
要执行翻转、放大和平移动画,您可以使用以下代码:
- (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
        }];
    }];
}

希望这能帮到你!


1
我希望只使用 transform 而不是 frame 来完成这个操作,以便我的视图子视图不会变形。 - edc1591
我知道如何构建变换,但我无法计算出图层的正确位置。 - edc1591
我认为你可以使用CGAffineTransformConcat()来进行纯变换,就像这里所示:https://dev59.com/y3NA5IYBdhLWcg3wC5Th 你想把视图显示在哪里? - sgonzalez
好的,我解决了动画问题,现在的问题是计算点数。请看我在原问题中的第四次编辑。 - edc1591
尝试使用UIView的.center属性。也许可以这样写:CGPoint detailFinalPoint = CGPointMake(gridView.center.x-detailView.frame.size.width/2, gridView.center.y-detailView.frame.size.height/2); - sgonzalez

1

好的,我解决了。这是我做的:

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"];

我正在使用 AQGridView 中的一个项目进行此操作。在我的代码示例中,view 是我正在动画化的 AQGridViewCell 实例。而 vc.view 则是我要显示的详细信息 UIViewController/UIView


我正在尝试使其在 iPhone 应用程序中工作。在运行此代码之前,您对详细视图做了什么?是否将详细视图控制器的视图添加到层次结构中?如果是这样,设置了什么框架?当前,当我运行此代码时,网格视图会出现一半翻转,但详细视图没有显示任何内容。 - hundreth
@hundreth 我将详细视图添加为网格视图的子视图并居中显示。 - edc1591

0

我强烈建议看一下this的帖子。

你不需要自己处理所有这些动画。

如果你使用UIView类方法transitionFromView:toView:duration:options:completion:并传入UIViewAnimationOptionTransitionFlipFromLeftUIViewAnimationOptionTransitionFlipFromRight - 无论你想要动画翻转的方向是哪个。

我已经使用这种方法实现了与MLB应用程序中所示相同的内容。你的from view将是网格中的单元格,而to view将是在单元格“背面”的东西。

希望这将减少你需要的整体代码量。


我正在尝试类似的事情,但遇到了困难。在视图翻转时,您是如何缩放和移动视图到正确位置的? - kyleplattner
我已经有一段时间没有看过这个了,但我认为它取决于你传递到transitionFromView:toView:duration:options:completion:方法中的fromViewtoView视图的框架。 - njkremer

0
我会使用UICollectionView和自定义的UICollectionViewCell,并通过其委托调用进行动画处理...这只是供其他人参考的一个例子。
#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];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接