控制器的转场动画
众所周知,iOS中的页面跳转方式有两种,一种是navigationController push/pop新页面,另一种是当前页面present/dismiss新页面
1. push/pop 转场动画
系统默认的push动画是从右往左推出新视图,pop则是从左往右消失
自定义实现步骤
a.控制器实现nagationController delegate的方法animationControllerForOperation:fromController:toController,返回一个实现了UIViewControllerAnimatedTransitionning对象,如果返回为nil,则是系统的默认实现
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { if ([NSStringFromClass(fromVC.class) isEqualTo:]) { return [CustomTransitioning new]; } return nil; }
b.自定义实现UIViewControllerAnimatedTransitioning协议的对象,实现自定义转场
@interface XWPageCoverTransition : NSObject<UIViewControllerAnimatedTransitioning> @end @implementation XWPageCoverTransition - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{ return 0.3; } /** * 如何执行过渡动画 */ - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ } @end
必须实现该协议的两个方法
transitionDuration: 返回转场时间
animationTransition: 转场动画的具体操作,以一个简单的例子来说明如何实现
// 从下到上显示 - (void)showFromBottomToTop:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *containerView = [transitionContext containerView]; CGRect toVCFrame = [transitionContext finalFrameForViewController:toVC]; [containerView addSubview:toVC.view]; [containerView sendSubviewToBack:toVC.view]; //对tempView做动画,避免bug; UIView *tempView = [toVC.view snapshotViewAfterScreenUpdates:YES]; tempView.frame = CGRectOffset(toVCFrame, 0, SCREEN_HEIGHT); [containerView addSubview:tempView]; //增加阴影 tempView.layer.shadowOffset = CGSizeMake(0, 1); tempView.layer.shadowColor = [UIColor lightGrayColor].CGColor; tempView.layer.shadowOpacity = 0.8; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ tempView.frame = toVCFrame; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; [tempView removeFromSuperview]; [containerView bringSubviewToFront:toVC.view]; }]; }
以上代码是自定义push从下到上显示,该方法包含一个transitionContext对象,我们来看看该对象的几个重要属性
-containerView 包含上下文的容器,动画在该容器中进行
-viewControllerForKey 获取fromVC/toVC
-finalFrameForViewController 获取fromVC/toVC的最终展示frame
一般的做法是根据转场类型push/pop做相应处理,通常是frame,alpha的的简单变化,也可以做复杂点的三维变化。
如果是push动画,A->B,fromVC是A,toVC是B;pop B,fromVC是B,toVC是A。每次变换container中必须添加toVC.view,截取该视图,对截取的视图做相应动画,动画结束后,恢复原始状态即可。
2.present/dismiss动画,默认的是从下到上呈现,以及从上到下消失
自定义实现步骤:
1.自定义的页面需要声明UIViewControllerTransitionningDelegate,并设置modelPresentationStyle为custom,同事还需实现相关的代理方法
@interface XWPresentedOneController ()<UIViewControllerTransitioningDelegate> @property (nonatomic, strong) XWInteractiveTransition *interactiveDismiss; @property (nonatomic, strong) XWInteractiveTransition *interactivePush; @end @implementation XWPresentedOneController - (void)dealloc{ NSLog(@"销毁了!!!!!"); } - (instancetype)init { self = [super init]; if (self) { self.transitioningDelegate = self; self.modalPresentationStyle = UIModalPresentationCustom; } return self; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{ return [XWPresentOneTransition transitionWithTransitionType:XWPresentOneTransitionTypePresent]; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{ return [XWPresentOneTransition transitionWithTransitionType:XWPresentOneTransitionTypeDismiss]; } - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator{ return _interactiveDismiss.interation ? _interactiveDismiss : nil; } - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator{ XWInteractiveTransition *interactivePresent = [_delegate interactiveTransitionForPresent]; return interactivePresent.interation ? interactivePresent : nil; } @end
UIViewControllerTransitionDelegate重要方法介绍
- animationControllerForPresentedController: present返回实现<UIViewControllerTransitioning>对象
- animationControllerForDismissedController: 返回自定义的dimiss对象
- interactionControllerForPresentation: present返回百分比动画
- interactionControllerForDismissal: dismiss返回百分比动画
百分比(交互式)动画,需定义UIPercentDrivenInteractiveTransition子类,绑定pan手势,根据手势的相应状态传递事件,本质上还是调用自定义实现的transition方法,因此没个transition完成动画的闭包中会有相应代码来回应交互式状态
/开始动画吧,使用产生弹簧效果的动画API [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.55 initialSpringVelocity:1.0 / 0.55 options:0 animations:^{ //首先我们让vc2向上移动 toVC.view.transform = CGAffineTransformMakeTranslation(0, -400); //然后让截图视图缩小一点即可 tempView.transform = CGAffineTransformMakeScale(0.85, 0.85); } completion:^(BOOL finished) { //使用如下代码标记整个转场过程是否正常完成[transitionContext transitionWasCancelled]代表手势是否取消了,如果取消了就传NO表示转场失败,反之亦然,如果不是用手势的话直接传YES也是可以的,我们必须标记转场的状态,系统才知道处理转场后的操作,否者认为你一直还在,会出现无法交互的情况,切记 [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; //转场失败后的处理 if ([transitionContext transitionWasCancelled]) { //失败后,我们要把vc1显示出来 fromVC.view.hidden = NO; //然后移除截图视图,因为下次触发present会重新截图 [tempView removeFromSuperview]; } }];
UIView的转场动画
1.直接调用系统api [UIView transitionWithView:duration:option:animation:^{}completion:^{}]
- transitionView 需要转场到的视图
- duration 动画时间
- option 转场类型
- aniamtion 动画块
- completion 动画结束回调
UIViewAnimationOptionTransitionNone // default UIViewAnimationOptionTransitionFlipFromLeft // 从左翻转 UIViewAnimationOptionTransitionFlipFromRight // 从右翻转 UIViewAnimationOptionTransitionCurlUp // 向上翻页 UIViewAnimationOptionTransitionCurlDown // 向下翻页 UIViewAnimationOptionTransitionCrossDissolve // 溶解 UIViewAnimationOptionTransitionFlipFromTop // 从上翻转 UIViewAnimationOptionTransitionFlipFromBottom // 从下翻转
2.使用CATransition 创建相应的animation,view.layer添加后直接在layer上渲染
CATransition的基本属性,以下属性均可以使用kvc调用
- type 转场类型
- subtype 转场的子类型
- duration 动画时间
- timeFunction 动画加速度
// type *1.kCATransitionMoveIn 新的视图把旧的视图掩盖 *2.kCATransitionPush 旧的视图移走,新的视图移进来 *3.kCATransitionFade 逐渐消失,相当于调整透明度,除了这没有方向,其他的都有 *4.kCATransitionReveal 旧的视图移走,显示出新的视图 //这类是API引入的,在苹果官网是不会承认的,所以不建议使用 *1.animation.type = @"cube"; //立方体效果 *2.animation.type = @"suckEffect";//犹如一块布被抽走 *3. animation.type = @"oglFlip"; //上下翻转效果 *4. animation.type = @"rippleEffect"; //滴水效果 *5. animation.type = @"pageCurl"; //向左翻页 *6.animation.type = @"pageUnCurl"; //向下翻页 // subtype kCATransitionFromBottom kCATransitionFromLeft kCATransitionFromRight kCATransitionFromTop // timeFunction CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionLinear CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseIn CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseOut CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseInEaseOut CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionDefault