iOS实现转场动画的3种方法示例
什么是转场动画
在NavigationController里push或pop一个ViewController,在TabBarController中切换到其他ViewController,以Modal方式显示另外一个ViewController,这些都是ViewControllerTransition。在storyboard里,每个ViewController是一个Scene,ViewControllerTransition便是从一个Scene转换到另外一个Scene,中文称呼其为「转场」。顾名思义,转场动画便是ViewControllerTransition过程中的动画效果。
在iOS7之前,我们只能使用系统提供的转场效果,大部分时候够用,但仅仅是够用而已,总归会有各种不如意的小地方,但我们却无力改变;iOS7开放了相关API允许我们对转场效果进行全面定制,这太棒了,自定义转场动画以及对交互手段的支持带来了无限可能。
本文主要给大家介绍了关于iOS实现转场动画的3种方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧
1.CATransition
CATransition是CAAnimation的子类,用于过渡动画或转场动画。为视图层移入移除屏幕提供转场动画。首先来看一下简单的Demo:
CATransition*animation=[CATransitionanimation]; animation.type=kCATransitionFade; animation.subtype=kCATransitionFromRight; animation.duration=1.0; //在window上执行CATransition,即可在ViewController转场时执行动画 [self.view.window.layeraddAnimation:animationforKey:@"kTransitionAnimation"]; AViewController*vc=[[AViewControlleralloc]init]; [selfpresentViewController:vcanimated:NOcompletion:nil];
将该动画添加到window.layer上,则会present或push时使用指定的转场动画。
其中最主要的两个属性就是type和subtype。
- type:转场动画的类型。
官方SDK只提供了四种转场动画的类型,即:
CA_EXTERNNSString*constkCATransitionFade; CA_EXTERNNSString*constkCATransitionMoveIn; CA_EXTERNNSString*constkCATransitionPush; CA_EXTERNNSString*constkCATransitionReveal;
私有的type:
NSString*constkCATransitionCube=@"cube"; NSString*constkCATransitionSuckEffect=@"suckEffect"; NSString*constkCATransitionOglFlip=@"oglFlip"; NSString*constkCATransitionRippleEffect=@"rippleEffect"; NSString*constkCATransitionPageCurl=@"pageCurl"; NSString*constkCATransitionPageUnCurl=@"pageUnCurl"; NSString*constkCATransitionCameraIrisHollowOpen=@"cameraIrisHollowOpen"; NSString*constkCATransitionCameraIrisHollowClose=@"cameraIrisHollowClose";
- subtype:动画类型的方向
CA_EXTERNNSString*constkCATransitionFromRight; CA_EXTERNNSString*constkCATransitionFromLeft; CA_EXTERNNSString*constkCATransitionFromTop; CA_EXTERNNSString*constkCATransitionFromBottom;
上面讲的是给window.layer添加transition,这样使得在present或push时使用指定的转场动画。
既然讲到这里了,就看一下把transition加在layer上。
看一下示例代码:
-(void)viewDidLoad{ [superviewDidLoad]; UIButton*button=[[UIButtonalloc]initWithFrame:CGRectMake(100,100,100,50)]; [buttonsetTitle:@"进入"forState:UIControlStateNormal]; button.backgroundColor=[UIColorredColor]; [buttonaddTarget:selfaction:@selector(buttonClicked)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:button]; _imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(100,300,150,150)]; [self.viewaddSubview:_imageView]; _imageView.backgroundColor=[UIColorredColor]; _imageArray=@[[UIImageimageNamed:@"成果秀1"],[UIImageimageNamed:@"点赞他人1"],[UIImageimageNamed:@"偷师学艺1"],[UIImageimageNamed:@"学会欣赏3"]]; _imageView.image=[UIImageimageNamed:@"成果秀1"]; } -(void)buttonClicked{ CATransition*animation=[CATransitionanimation]; animation.type=@"cube"; animation.subtype=kCATransitionFromRight; animation.duration=1.0; //换图片的时候使用转场动画 [self.imageView.layeraddAnimation:animationforKey:nil]; //cycletonextimage UIImage*currentImage=self.imageView.image; NSUIntegerindex=[self.imageArrayindexOfObject:currentImage]; index=(index+1)%[self.imageArraycount]; self.imageView.image=self.imageArray[index]; }
2.transitionFromViewController
UIViewController自带的方法:
transitionFromViewController:toViewController:duration:options:animations:completion:这个转场动画是用在当一个父视图控制器中有几个childViewController,当要在这几个子视图控制器之间切换时就可以用这个方法。
AViewController*a=self.childViewControllers[0]; BViewController*b=self.childViewControllers[1]; CViewController*c=self.childViewControllers[2]; //Curl翻页效果 //UIViewAnimationOptionTransitionCurlUp,UIViewAnimationOptionTransitionCurlDown //Flip翻转效果 //UIViewAnimationOptionTransitionFlipFromLeft,UIViewAnimationOptionTransitionFlipFromRight //UIViewAnimationOptionTransitionFlipFromTop,UIViewAnimationOptionTransitionFlipFromDown [selftransitionFromViewController:_currentViewController toViewController:b duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{ }completion:^(BOOLfinished){ }];
3.TransitionAnimation
1UINavigationControllerDelegate+UIViewControllerAnimatedTransitioning
在UINavigationController的转场动画中,要指定UINavigationControllerDelegate对象:
self.navigationController.delegate=self; [self.navigationControllerpushViewController:itemVCanimated:YES];
UINavigationControllerDelegate主要有以下两个协议方法:
//pop -(nullableid)navigationController:(UINavigationController*)navigationController interactionControllerForAnimationController:(id )animationControllerNS_AVAILABLE_IOS(7_0); //push -(nullableid )navigationController:(UINavigationController*)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVCNS_AVAILABLE_IOS(7_0);
首先创建一个基类PDAnimatorBaseTransition实现UIViewControllerAnimatedTransitioning协议的方法。
UIViewControllerAnimatedTransitioning协议的方法有:
//动画持续时间 -(NSTimeInterval)transitionDuration:(nullableid)transitionContext; //转场动画实现细节 -(void)animateTransition:(id )transitionContext; 动画结束时调用 -(void)animationEnded:(BOOL)transitionCompleted;
PDAnimatorBaseTransition.h
#import#import typedefNS_ENUM(NSInteger,PDAnimationType){ animationTypePresent=0, animationTypeDismiss, animationTypePush, animationTypePop, }; @interfacePDAnimatorBaseTransition:NSObject @property(nonatomic,assign)PDAnimationTypeanimationType; @property(nonatomic,strong)UIView*containerView; @property(nonatomic,strong)UIViewController*from; @property(nonatomic,strong)UIViewController*to; @property(nonatomic,strong)UIView*fromView; @property(nonatomic,strong)UIView*toView; @property(nonatomic,weak)id transitionContext; @end
PDAnimatorBaseTransition.m
#import"PDAnimatorBaseTransition.h" @interfacePDAnimatorBaseTransition() @end @implementationPDAnimatorBaseTransition #pragmamark-required -(NSTimeInterval)transitionDuration:(nullableid)transitionContext{ return1.f; } -(void)animateTransition:(id )transitionContext{ _transitionContext=transitionContext; _containerView=[transitionContextcontainerView]; _from=[transitionContextviewControllerForKey:UITransitionContextFromViewControllerKey]; _to=[transitionContextviewControllerForKey:UITransitionContextToViewControllerKey]; if([transitionContextrespondsToSelector:@selector(viewForKey:)]){ _fromView=[transitionContextviewForKey:UITransitionContextFromViewKey]; _toView=[transitionContextviewForKey:UITransitionContextToViewKey]; }else{ _fromView=_from.view; _toView=_to.view; } if(self.animationType==animationTypePresent){ [selfanimationPresent]; }elseif(self.animationType==animationTypeDismiss){ [selfanimationDismiss]; }elseif(self.animationType==animationTypePop){ [selfanimationPop]; }else{ [selfanimationPush]; } } #pragmamark-optional //动画结束时回调 -(void)animationEnded:(BOOL)transitionCompleted{ } -(void)animationPresent{ } -(void)animationDismiss{ } -(void)animationPop{ } -(void)animationPush{ }
然后创建子类PDAnimatorPUshPopTransition继承自PDAnimatorBaseTransition,实现-(void)animationPush,-(void)animationPop方法。
PDAnimatorPUshPopTransition.h
#import"PDAnimatorBaseTransition.h" #import@interfacePDAnimatorPUshPopTransition:PDAnimatorBaseTransition @property(nonatomic,assign)CGPointitemCenter; @property(nonatomic,assign)CGSizeitemSize; @property(nonatomic,strong)NSString*imageName; @end
PDAnimatorPUshPopTransition.m
#import"PDAnimatorPUshPopTransition.h" @implementationPDAnimatorPUshPopTransition -(instancetype)init{ self=[superinit]; if(self){ } returnself; } -(NSTimeInterval)transitionDuration:(nullableid)transitionContext{ return5.f; } -(void)animateTransition:(id )transitionContext{ [superanimateTransition:transitionContext]; } -(void)animationPush{ NSTimeIntervalduration=[selftransitionDuration:self.transitionContext]; __weaktypeof(self)weakSelf=self; self.containerView.backgroundColor=[UIColorlightGrayColor]; UIImageView*imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(0,0,100,160)]; imageView.image=[UIImageimageNamed:self.imageName]; imageView.center=_itemCenter; CGFloatinitialScale=_itemSize.width/CGRectGetWidth(imageView.frame); CGAffineTransformtransform=CGAffineTransformIdentity; transform=CGAffineTransformScale(transform,initialScale,initialScale); transform=CGAffineTransformRotate(transform,M_PI); imageView.layer.affineTransform=transform; //imageView.transform=CGAffineTransformMakeScale(initialScale,initialScale); [self.containerViewaddSubview:imageView]; self.toView.frame=[self.transitionContextfinalFrameForViewController:self.to]; CGPointfinalCenter=self.toView.center; self.toView.center=finalCenter; self.toView.alpha=0.0; //这一句一定要 [self.containerViewaddSubview:self.toView]; [UIViewanimateWithDuration:durationdelay:0usingSpringWithDamping:0.5initialSpringVelocity:0options:UIViewAnimationOptionCurveLinearanimations:^{ imageView.layer.affineTransform=CGAffineTransformIdentity; imageView.center=finalCenter; self.fromView.alpha=0.0; self.containerView.backgroundColor=[UIColorredColor]; }completion:^(BOOLfinished){ [imageViewremoveFromSuperview]; weakSelf.toView.alpha=1.0f; weakSelf.fromView.alpha=1.0f; [weakSelf.transitionContextcompleteTransition:![weakSelf.transitionContexttransitionWasCancelled]]; }]; } -(void)animationPop{ NSTimeIntervalduration=[selftransitionDuration:self.transitionContext]; __weaktypeof(self)weakSelf=self; self.toView.frame=[self.transitionContextfinalFrameForViewController:self.to]; [self.containerViewinsertSubview:self.toViewbelowSubview:self.fromView]; self.fromView.alpha=0.0; self.fromView.backgroundColor=[UIColorclearColor]; [UIViewanimateWithDuration:durationdelay:0usingSpringWithDamping:0.5initialSpringVelocity:0options:UIViewAnimationOptionCurveLinearanimations:^{ CGFloatinitialScale=_itemSize.width/200; weakSelf.fromView.transform=CGAffineTransformMakeScale(initialScale,initialScale); weakSelf.fromView.center=weakSelf.itemCenter; weakSelf.toView.alpha=1.0f; }completion:^(BOOLfinished){ weakSelf.fromView.alpha=0.0f; [weakSelf.transitionContextcompleteTransition:![weakSelf.transitionContexttransitionWasCancelled]]; }]; } @end
然后我们在需要push的地方实现UINavigationControllerDelegate的协议方法:
-(nullableid)navigationController:(UINavigationController*)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVCNS_AVAILABLE_IOS(7_0){ PDAnimatorPUshPopTransition*animationTransition=[[PDAnimatorPUshPopTransitionalloc]init]; if(operation==UINavigationControllerOperationPush){ animationTransition.animationType=animationTypePush; }elseif(operation==UINavigationControllerOperationPop){ animationTransition.animationType=animationTypePop; } NSArray*indexPaths=[self.collectionViewindexPathsForSelectedItems]; if(indexPaths.count==0){ returnnil; } NSIndexPath*selectedIndexPath=indexPaths[0]; UICollectionViewCell*cell=[self.collectionViewcellForItemAtIndexPath:selectedIndexPath]; //一定要加上convertPoint:toView:操作 animationTransition.itemCenter=[self.collectionViewconvertPoint:cell.centertoView:self.view]; animationTransition.itemSize=cell.frame.size; animationTransition.imageName=[NSStringstringWithFormat:@"%ld",(long)selectedIndexPath.item]; returnanimationTransition; }
2UIViewControllerTransitioningDelegate+UIViewControllerAnimatedTransitioning
首先需要设置被present的Controller的transitionDelegate
DemoViewControllerTransitionPresentedViewController*presentedVC=[[DemoViewControllerTransitionPresentedViewControlleralloc]init]; presentedVC.transitionDelegate=self; [selfpresentViewController:presentedVCanimated:YEScompletion:nil];
UIViewControllerTransitioningDelegate的代理的协议方法有:
//prenent -(id)animationControllerForPresentedController:(UIViewController*)presentedpresentingController:(UIViewController*)presentingsourceController:(UIViewController*)source; //pop -(id)animationControllerForDismissedController:(UIViewController*)dismissed; //prenent -(id)interactionControllerForPresentation:(id)animator; //pop -(nullableid)interactionControllerForDismissal:(id)animator;
创建子类PDAnimationPresentTransitio继承自基类PDAnimatorBaseTransition,实现-(void)animationPresent,-(void)animationDismiss方法。
PDAnimationPresentTransition.h
#import"PDAnimatorBaseTransition.h" @interfacePDAnimationPresentTransition:PDAnimatorBaseTransition @end
PDAnimationPresentTransition.m
#import"PDAnimationPresentTransition.h" @implementationPDAnimationPresentTransition -(NSTimeInterval)transitionDuration:(nullableid)transitionContext{ return1.f; } -(void)animateTransition:(id )transitionContext{ [superanimateTransition:transitionContext]; } -(void)animationPresent{ NSTimeIntervalduration=[selftransitionDuration:self.transitionContext]; __weaktypeof(self)weakSelf=self; self.toView.frame=[self.transitionContextinitialFrameForViewController:self.to]; self.fromView.frame=[self.transitionContextinitialFrameForViewController:self.from]; CGAffineTransformtransform=CGAffineTransformIdentity; transform=CGAffineTransformScale(transform,0.001,0.001); self.toView.layer.affineTransform=transform; [self.containerViewaddSubview:self.toView]; self.toView.alpha=0.0; [UIViewanimateWithDuration:durationdelay:0usingSpringWithDamping:0.6initialSpringVelocity:0options:UIViewAnimationOptionCurveEaseInOutanimations:^{ self.toView.layer.affineTransform=CGAffineTransformIdentity; self.toView.frame=[self.transitionContextfinalFrameForViewController:self.to]; self.toView.alpha=1.0; }completion:^(BOOLfinished){ BOOLwasCancelled=[weakSelf.transitionContexttransitionWasCancelled]; [weakSelf.transitionContextcompleteTransition:!wasCancelled]; }]; }
然后我们在需要present的地方实现UIViewControllerTransitioningDelegate的代理方法。
-(nullableid)animationControllerForPresentedController:(UIViewController*)presentedpresentingController:(UIViewController*)presentingsourceController:(UIViewController*)source{ PDAnimationPresentTransition*animationTransition=[[PDAnimationPresentTransitionalloc]init]; animationTransition.animationType=animationTypePresent; returnanimationTransition; } -(nullableid )animationControllerForDismissedController:(UIViewController*)dismissed{ PDAnimationPresentTransition*animationTransition=[[PDAnimationPresentTransitionalloc]init]; animationTransition.animationType=animationTypePresent; returnanimationTransition; }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。