ios 转场动画的制作

直接看转场动画的协议时有点迷糊,做了一个简单的demo记录下理解过程

一、如何更改动画方式

站在自己的角度,最简单的理解是,要想制作一个自定义的转场动画,来避开原生的push和present的效果,则要更改系统默认动画的代理。

1.如果你使用的是navigationController的pushViewController方法,则要更改navigationController的delegate,并在delegate方法:

- (nullableid)navigationController:(UINavigationController*)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation

fromViewController:(UIViewController*)fromVC

toViewController:(UIViewController*)toVC;

{

return[customerAnimator new];//返回一个自定义的动画执行者

}

2.如果你使用的是[currentVCpresentViewController:newVCanimated:YEScompletion:nil];来present新页面的话,则需要重新设置newVC的transitioningDelegate这个代理是实现了UIViewControllerTransitioningDelegate协议的对象并在delegate中实现协议的以下两个方法

- (nullableid)animationControllerForDismissedController:(UIViewController*)dismissed;

{

return[customerAnimator new];//返回一个自定义的动画执行者,在customerAnimator才实现真正的动画效果,此方法是这个页面dismiss的之后询问的代理方法,问动画由设来执行。

}

- (nullableid)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source;

{

return[customerAnimator new];//返回一个自定义的动画执行者,此方法在页面出现时询问,问出现的动画由谁来执行。

}


二、动画的实际效果怎么实现

从上面的协议方法中可以看出,协议最终都要求返回一个遵循UIViewControllerAnimatedTransitioning协议的对象,即customerAnimator,这个对象充当动画的执行者角色。

也就是说,这个执行者必须按照协议规定的样子去执行转场,这个animator必须实现的两个协议方法是:

//1.执行动画所需要的时间

- (NSTimeInterval)transitionDuration:(nullableid)transitionContext;

//2.转场动画效果具体实现在这个方法中去实现

- (void)animateTransition:(id)transitionContext;

所以可以看出,整个过程中核心是animator(动画的执行者)在起作用,核心方法是- (void)animateTransition:(id)transitionContext ,负责实现实际的效果实现

//简单的示例

- (void)animateTransition:(id)transitionContext {

//如何切换两个View,设置和动画写在此处

//toVC

UIViewController*toVC = [transitionContextviewControllerForKey:UITransitionContextToViewControllerKey];

//finally rect

CGRectfinallyRect = [transitionContextfinalFrameForViewController:toVC];

toVC.view.frame=CGRectOffset(finallyRect,0, [UIScreenmainScreen].bounds.size.height);

//3

[[transitionContextcontainerView]addSubview:toVC.view];

//4

[UIViewanimateWithDuration:[selftransitionDuration:transitionContext]delay:0.0options:UIViewAnimationOptionCurveLinearanimations:^{

toVC.view.frame= finallyRect;

}completion:^(BOOLfinished) {

[transitionContextcompleteTransition:YES];

}];

}



三、基于手势的转场动画

当在animator中实现了动画效果后,要想在手指向右滑动的过程中,动画也跟着手指的滑动程度去更新动画的执行程度,则需要实现一个代理方法,用于返回标志动画执行的百分比的实例。

同样,如果是使用UIviewController presentViewController 的方式 则是实现UIViewControllerTransitioningDelegate协议的方法

- (nullableid)interactionControllerForDismissal:(id)animator{

_persentDriver =[UIPercentDrivenInteractiveTransition new];

return_persentDriver;//此实例中纪录了动画执行的persent

}

//用于提供消失的时候的手势百分比

如果是使用navigationController的push方法将viewController推出的,则需要实现naviagtionControllerDelegate协议的

- (nullableid)navigationController:(UINavigationController*)navigationController interactionControllerForAnimationController:(id) animationController {

_persentDriver =[UIPercentDrivenInteractiveTransition new];

return_persentDriver;

}

代理方法

为了达到手在滑动的过程中动画跟着手指执行,需要在给viewontroller的view加一个滑动手势


UIPanGestureRecognizer*panGesture = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(handPanGesture:)];

[self.viewaddGestureRecognizer:panGesture];

- (void)hanPanGesture:(UIPanGestureRecognizer*)gesture {

     CGPointpoint = [gesturetranslationInView:_viewController.view];

     switch(gesture.state) {

           caseUIGestureRecognizerStateBegan:

           {

                if(point.y>0) {

                       if(![self isBePresent])

                                //push进来的

                               [self.navigationControllerpopViewControllerAnimated:YES];

                        }else{

                                 //present进来的

                                  [selfdismissViewControllerAnimated:YEScompletion:^{

                                    }];

                       }

                }

}                                                                                                                                            break;                                                                                                                                  case  UIGestureRecognizerStateChanged:                                                                        {                                                                                                                                                    CGFloatpersent = point.y/200.0;                                                                                          [_persentDriverupdateInteractiveTransition:persent];//更新动画的百分比                   }                                                                                                                                          break;                                                                                                                                  case  UIGestureRecognizerStateCancelled:                                                                      case  UIGestureRecognizerStateEnded:                                                                             {                                                                                                                                               [_persentDriverfinishInteractiveTransition];                                                                     }                                                                                                                                    break;                                                                                        

 default:

 break;                                                                                                                                   } }

- (BOOL)isBePresented {

        if(self.navigationController) {

               NSArray*viewcontrollers=self.navigationController.viewControllers;

              if(viewcontrollers.count>1) {

                       if([viewcontrollersobjectAtIndex:viewcontrollers.count-1]==self) {

                                //push方式

                                returnNO;

                       }

             }else{

                 //present方式

                returnYES;

            }

     }

returnNO;

}

将手势的执行和persentDriver数据更新链接起来后,UINaviagtionControllerDelegate和UIViewControllerTransitioningDelegate

协议中返回的_persentDriver才可以带有手势的执行比例,这样动画就可以跟着手指滑动的程度来更新了。

你可能感兴趣的:(ios 转场动画的制作)