实现自定义animation来显示iPad上的指定视图的模态视图

在iPad上我们有更多的空间可以使用,所以呈现全屏模式视图并不理想。

我知道如何在新的formSheet中呈现模态视图,并且可以在这个问题上find一个紧密的方法: iPad iTunes Animation

问题是,你不能selectanimation将来自哪里,所以它只是默认,并从中心出现,我想定制它,使其显示从一个特定的位置。

这个animation的最好的例子可以在这个video的前几秒看到

如果任何人都可以使用代码,教程或文档指向正确的方向,我将不胜感激!

更新:

经过一番调查后,我发现这可以用第一部分的图层和核心animation来完成。 然后animation它的formSheet模态视图,但我还是不太明白如何实现它,希望你们可以帮助!

我所做的是为UIViewController创build一个新的类别,如下所示

的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 

这非常简单。 请让我知道这是否有助于你。

UPDATE

我更新了使用animation块的答案,而不是[UIView beginAnimations:nil context:nil]; / [UIView commitAnimations]对。

看起来像是你翻译(移动)一个CALayer同时缩小它,并在同一时间围绕y轴旋转。 尝试这个:

 NSValue *initialTransformValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; CATransform3D translation = CATransform3DMakeTranslation(finalPoint.x, finalPoint.y, 0.0); CATransform3D scalingAndTranslation = CATransform3DScale(translation, kMyScalingFactor, kMyScalingFactor, 1.0); CATransform3D finalTransform = CATransform3DRotate(scalingAndTranslation, myRotationAngle, 0.0, 1.0, 0.0); NSArray *keyFrameValues = [NSArray arrayWithObjects:initialTransformValue, [NSValue valueWithCATransform3D:finalTransform], nil]; CAKeyframeAnimation *myAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; myAnimation.values = keyFrameValues; myAnimation.duration = kMyAnimationDuration; myAnimation.delegate = self; myAnimation.removedOnCompletion = NO; myAnimation.fillMode = kCAFillModeForwards; [myLayer addAnimation:myAnimation forKey:@"myAnimationKey"]; 
  • finalPoint应该是finalPoint 坐标空间中的一个CGPoint
  • kMyScalingFactor的缩放比例应该小于1.0,放大比例应该大于1.0。
  • myRotationAngle应该是弧度。 使用正值顺时针旋转和逆时针旋转负值。

您还需要实现animation终止处理程序以使animation“粘贴”:

 - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { myLayer.transform = finalTransform; myLayer removeAnimationForKey:@"myAnimationKey"]; } 

希望这可以帮助。

我只是通过animation视图来完成这个工作。

1)相册作品在网格中。
2)使用翻转animation转换专辑作品的视图。
3)animation在屏幕上移动的视图。

我很快把它扔在一起。 假设你有一个空的视图控制器和3个视图。

 - (void)viewDidLoad { [super viewDidLoad]; [self performSelector:@selector(transition) withObject:nil afterDelay:1]; albumArtworkSquare = [[UIView alloc] initWithFrame:CGRectMake(400, 500, 300, 300)]; albumArtworkSquare.backgroundColor = [UIColor blackColor]; [self.view addSubview:albumArtworkSquare]; frontViewOfAlbumArtwork = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]; frontViewOfAlbumArtwork.backgroundColor = [UIColor blueColor]; [albumArtworkSquare addSubview:frontViewOfAlbumArtwork]; backViewToTransitionTo = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]; backViewToTransitionTo.backgroundColor = [UIColor grayColor]; } - (void)transition { [UIView animateWithDuration:2 animations:^{ albumArtworkSquare.frame = CGRectMake(10, 500, 300, 300); }]; [UIView transitionFromView:frontViewOfAlbumArtwork toView:backViewToTransitionTo duration:2 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished) { [frontViewOfAlbumArtwork removeFromSuperview]; [albumArtworkSquare addSubview:backViewToTransitionTo]; }]; } 

Mihai的答案不会像iPad itunesanimation那样处理翻转。 我改变了一点点来翻转视图。 你不需要各种疯狂的CAAnimation,只需要一些内置的UIViewanimationfunction。

 #import <QuartzCore/QuartzCore.h> @interface UIViewController (ShowModalFromView) - (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view; @end @implementation UIViewController (ShowModalFromView) - (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view { NSTimeInterval scaleSpeed = 0.3; NSTimeInterval flipSpeed = 0.4; UIView __weak *containerView = view.superview; view.autoresizesSubviews = YES; [self presentModalViewController:modalViewController animated:NO]; UIView __weak *presentedView = modalViewController.view.superview; //intead of show the actual view of modalViewController, we are showing the snapshot of it to avoid layout problem UIGraphicsBeginImageContext(presentedView.bounds.size); [presentedView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage* modalSnapshot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIView __weak *originalSuperView = presentedView.superview; CGRect originalFrame = presentedView.frame; CGRect frameInContainer = [containerView convertRect:originalFrame fromView:originalSuperView]; [presentedView removeFromSuperview]; UIImageView* snapshotView = [[UIImageView alloc] initWithImage:modalSnapshot]; snapshotView.autoresizingMask = UIViewAutoresizingNone; [containerView bringSubviewToFront:view]; [UIView animateWithDuration:scaleSpeed delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionBeginFromCurrentState animations: ^{ [UIView animateWithDuration:scaleSpeed delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations: ^{ view.frame = frameInContainer; } completion:nil ]; } completion:^(BOOL finished) { [UIView setAnimationBeginsFromCurrentState:YES]; [UIView transitionWithView:view duration:flipSpeed options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionTransitionFlipFromRight animations: ^{ snapshotView.frame = view.bounds; [view addSubview:snapshotView]; } completion:^(BOOL finished) { [originalSuperView addSubview:presentedView]; [snapshotView removeFromSuperview]; } ]; }]; } 

您可以使用此..对于基于导航控制器的应用程序..

 YourViewController *obj = [[YourViewController alloc]initWithNibName:@"YourViewControllerXIBName" bundle:nil]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 1.0]; [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:YES]; [self.navigationController pushViewController:obj animated:NO]; [UIView commitAnimations]; [obj release]; 

我在我的一个项目中做了一些非常相似的事情,有一个专辑艺术的网格。 这是我正在采取的方法。 关键是使用CAAnimationGroup

1)整个animation将包括同时缩放,旋转和沿着path移动 – 首先是专辑封面层,然后是模式视图层。

2)将专辑艺术图层翻转90度,缩放一点,从当前位置移动到预定位置。 此时它将消失(垂直于屏幕)。

3)添加模态视图。 将模式视图缩放并转换为专辑封面在步骤1中定位的确切位置。

4)通过缩放,旋转和沿着path移动来填充屏幕,从这个位置对模态视图进行animation处理。

5)删除模态视图。

6)现在的模态视图没有animation。

7)select的path通常会添加屏幕的中心作为控制点。 但是,这可以根据您希望animation显示的方式进行更改。

下面是一个可以看到animation组使用的function。 希望这可以帮助你。 我仍然没有想出如何避免由导航栏和标签栏虽然animation剪辑。 🙂

 + (void)animateWithCurrentView:(UIView *)currentView { #define kResizeKey @"bounds.size" #define kPathMovement @"position" #define kRotation @"transform" #define kGroupAnimation @"subviewBeingAnimated" #define kLayerAnimation @"animateLayer" //flip the view by 180 degrees in its place first. currentView.layer.transform = CATransform3DRotate(currentView.layer.transform,radians(180), 0, 1, 0); //set the anchor point so that the view rotates on one of its sides. currentView.layer.anchorPoint = CGPointMake(0.0, 0.5); /** * Set up scaling */ CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey]; //we are going to fill the screen here. So 320,480 [resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(320, 480)]]; resizeAnimation.fillMode = kCAFillModeForwards; resizeAnimation.removedOnCompletion = NO; /** * Set up path movement */ UIBezierPath *movePath = [UIBezierPath bezierPath]; //the control point is now set to centre of the filled screen. Change this to make the path different. CGPoint ctlPoint = CGPointMake(160.0, 240.0); //This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here. [movePath moveToPoint:CGPointMake(320, 60)]; //The anchor point is going to end up here at the end of the animation. [movePath addQuadCurveToPoint:CGPointMake(0, 240) controlPoint:ctlPoint]; CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement]; moveAnim.path = movePath.CGPath; moveAnim.removedOnCompletion = YES; /** * Setup rotation animation */ CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation]; //start from 180 degrees (done in 1st line) CATransform3D fromTransform = CATransform3DMakeRotation(radians(180), 0, 1, 0); //come back to 0 degrees CATransform3D toTransform = CATransform3DMakeRotation(radians(0), 0, 1, 0); //This is done to get some perspective. CATransform3D persp1 = CATransform3DIdentity; persp1.m34 = 1.0 / -3000; fromTransform = CATransform3DConcat(fromTransform, persp1); toTransform = CATransform3DConcat(toTransform,persp1); rotateAnimation.toValue = [NSValue valueWithCATransform3D:toTransform]; rotateAnimation.fromValue = [NSValue valueWithCATransform3D:fromTransform]; //rotateAnimation.duration = 2; rotateAnimation.fillMode = kCAFillModeForwards; rotateAnimation.removedOnCompletion = NO; /** * Setup and add all animations to the group */ CAAnimationGroup *group = [CAAnimationGroup animation]; [group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]]; group.fillMode = kCAFillModeForwards; group.removedOnCompletion = NO; group.duration = 0.7f; group.delegate = self; [group setValue:currentView forKey:kGroupAnimation]; /** * ...and go */ [currentView.layer addAnimation:group forKey:kLayerAnimation]; } 

如果您可以首先获取模态视图,以显示您想要的地方没有animation。 应该向前迈进,并且设置view.superview的边界/框架可以用于表单样式。

如果你已经解决了,那么你可以执行你的“纯视图”animation来获取它,然后移除视图,并“呈现”模态控制器(控制该视图),以便瞬时交换控制器到视图的逻辑控制层次结构。