天天看点

玩转iOS转场动画(二)

    首先我们需要实现TransDelegate类中的如下两个函数:

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{

   return [AniObject new];

}

- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator{

   //遵守了UIViewControllerInteractiveTransitioning协议的对象

   return self.object;

UIViewControllerInteractiveTransitioning协议用来处理可交互的转场动画的具体表现,需要注意,因为使用的是可交互的转场动画,UIViewControllerAnimatedTransitioning协议中的animateTransition:方法可以空实现。下面我们再创建一个遵守UIViewControllerInteractiveTransitioning协议的类,比如命名为IntObject,上面代码中的self.object即是这个类的示例,IntObject.h文件如下:

@interface IntObject : NSObject<UIViewControllerInteractiveTransitioning>

-(void)updateAniProgress:(CGFloat)progress;

-(void)finish;

-(void)cancel;

@end

IntObject.m文件实现如下:

@interface IntObject()

@property(nonatomic,strong)id<UIViewControllerContextTransitioning> context;

@implementation IntObject

//这个函数用来保存transitionContext

-(void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext{

   self.context = transitionContext;

   //跳转的界面

   UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

   UIViewController * fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

   //最终的位置

   toVC.view.frame = [transitionContext finalFrameForViewController:toVC];

   //添加到内容视图

   [[transitionContext containerView]insertSubview:toVC.view belowSubview:fromVC.view];

//更新动画状态

-(void)updateAniProgress:(CGFloat)progress{

   UIView *frameVC = [self.context viewForKey:UITransitionContextFromViewKey];

   CGRect fR = CGRectMake( [UIScreen mainScreen].bounds.size.width*progress, 0, [UIScreen mainScreen].bounds.size.width,  [UIScreen mainScreen].bounds.size.height);

   frameVC.frame = fR;

//结束转场

-(void)finish{

   [UIView animateWithDuration:0.2 animations:^{

       UIView *frameVC = [self.context viewForKey:UITransitionContextFromViewKey];

       frameVC.frame = CGRectMake([UIScreen mainScreen].bounds.size.width, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

   } completion:^(BOOL finished) {

       [self.context completeTransition:YES];

   }];

//取消转场

-(void)cancel{

       frameVC.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

       [self.context cancelInteractiveTransition];

下面我们来添加手势,在ViewController2类中添加如下代码:

@interface ViewController2 ()

@property(nonatomic,strong)UIPanGestureRecognizer * pan;

@implementation ViewController2

- (void)viewDidLoad {

   [super viewDidLoad];

   self.view.backgroundColor = [UIColor redColor];

   [self.view addGestureRecognizer:self.pan];

   // Do any additional setup after loading the view.

-(void)pan:(UIPanGestureRecognizer *)pan{

   CGPoint translatedPoint = [pan translationInView:self.view];

   CGFloat persent =  translatedPoint.x /  [[UIScreen mainScreen]bounds].size.width;

   if (persent<0) {

       return;

   }

   persent = fabs(persent);

   IntObject * obj = [(TransDelegate *)self.transitioningDelegate object];

   switch (pan.state) {

       case UIGestureRecognizerStateBegan:{

           [self dismissViewControllerAnimated:YES completion:nil];

           break;

       }

       case UIGestureRecognizerStateChanged:{

           //手势过程中,通过updateInteractiveTransition设置pop过程进行的百分比

           [obj updateAniProgress:persent];

       case UIGestureRecognizerStateEnded:{

           //手势完成后结束标记并且判断移动距离是否过半,过则finishInteractiveTransition完成转场操作,否者取消转场操作

           if (persent > 0.5) {

               [obj finish];

           }else{

               [obj cancel];

           }

       default:

-(UIPanGestureRecognizer *)pan{

   if (!_pan) {

       _pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];

   return _pan;

手势效果如下:

其实,上面演示的是我们自己创建了一个类来实现UIViewControllerInteractiveTransitioning协议,其实系统也为我们提供一个类:UIPercentDrivenInteractiveTransition类,我们可以直接调用这个类的如下3个函数而不需要我们自己重写了,但是必须实现UIViewControllerAnimatedTransitioning协议中的transitionContext函数来实现动画效果。

- (void)updateInteractiveTransition:(CGFloat)percentComplete;

- (void)cancelInteractiveTransition;

- (void)finishInteractiveTransition;

其实现原理与我们上面进行完全的自定义是一样的。

三、导航转场动画的自定义

   导航转场动画的原理与模态跳转转场动画的原理基本是一致的,不同的我们需要设置UINavigationController实例的delegate为遵守UINavigationControllerDelegate协议的类对象。之后实现如下两个函数:

//设置转场的动画不论是push或pop 返回nil 则使用系统默认的导航转场动画

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController

                                           animationControllerForOperation:(UINavigationControllerOperation)operation

                                                        fromViewController:(UIViewController *)fromVC

                                                          toViewController:(UIViewController *)toVC  {

   NSLog(@"sss");

   return nil;

//设置可交互的转场动画

- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController

                                  interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{

   NSLog(@"aaa");

可以看到 animationControllerForOperation:函数依然需要返回一个遵守了UIViewControllerAnimatedTransitioning协议的对象,使用方式和前面所介绍的模态跳转自定义转场一模一样。UINavigationControllerOperation这个枚举将告知开发者导航所做的操作,如下:

typedef NS_ENUM(NSInteger, UINavigationControllerOperation) {

   UINavigationControllerOperationNone, //无

   UINavigationControllerOperationPush, //push操作

   UINavigationControllerOperationPop,  //pop操作

};

实现UIViewControllerInteractiveTransitioning协议如下:

   [self.context updateInteractiveTransition:progress];

     [self.context finishInteractiveTransition];

       [self.context completeTransition:NO];

如此即可以轻松实现可交互的自定义导航动画。

四、UITabBarController的转场动画

   UITabbar也可以进行转场动画的自定义,需要设置UITabBarController的delegate并实现协议中的如下两个函数:

//设置非交互的转场动画

- (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController

                    animationControllerForTransitionFromViewController:(UIViewController *)fromVC

                                                      toViewController:(UIViewController *)toVC  {

//设置交互的转场动画

- (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController

                              interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController{

这两个函数的应用和导航自定义动画基本是一致的,这里就不再列举代码,简单的效果见下图:

继续阅读