UIViewController过场动画

UIViewController过场动画_第1张图片
201410211713.png
UIViewController过场动画_第2张图片
ControllAnimation.gif

还是先看效果图。
同样它的原型也是我在cocoaChina上看到的,但那位大哥是将这两个动画分别放在presentViewControl和navigationViewControl中,我的这个就是结合了一下,顺便看怎么去写试图控制器之间的过场动画。
在控制器中需要实现的协议有:

//UIViewControllerTransitioningDelegate对应presentViewController,
//UINavigationControllerDelegate对应的则是navigationViewController.
UIViewControllerTransitioningDelegate ,UINavigationControllerDelegate

我的这个是在presentViewController中,则在进入另一个视图前:

- (void)animationBtnTap {
    
    CustomAnimationVC *vc = [CustomAnimationVC new];
    vc.transitioningDelegate = self;
    [self presentViewController:vc animated:YES completion:nil];
}

而我们需要重写协议中的方法有:

-(id)animationControllerForPresentedController:(UIViewController *)presented
                                                                 presentingController:(UIViewController *)presenting
                                                                     sourceController:(UIViewController *)source {
    
    modalAnimation.type = AnimationTypePresent;
    return modalAnimation;
}

返回的是我自定义的animation(可以用一个继承NSObject的类ModalAnimation并实现UIViewControllerAnimatedTransitioning中方法。),而上面的方法中需要重写UIViewControllerAnimatedTransitioning中方法:

-(void)animateTransition:(id)transitionContext {
    NSAssert(NO, @"animateTransition: should be handled ");
}

-(NSTimeInterval)transitionDuration:(id)transitionContext {
    return 1.0;
}

以上这两种方法是必需的。
present:

- (void)animateTransition:(id)transitionContext {

    if (self.type == AnimationTypePresent) {
        UIView *containView = [transitionContext containerView];
        UIView *modalView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
        [containView addSubview:modalView];
        [containView bringSubviewToFront:modalView];
        
        modalView.frame = CGRectMake(40, containView.centerY, containView.width - 40 *2, 100);
        [UIView animateWithDuration:1.0 delay:0.0 usingSpringWithDamping:0.8 initialSpringVelocity:1.0 options:0 animations:^{
            modalView.frame = CGRectMake(0, 0, containView.width, containView.height);
            //modalView.center = containView.center;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
}

只是简单的改变frame。

else {
        UIView *containerView = [transitionContext containerView];
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        
        UIView *fromSnapShot = [fromViewController.view snapshotViewAfterScreenUpdates:NO];
        fromSnapShot.frame = fromViewController.view.frame;
        [containerView insertSubview:fromSnapShot aboveSubview:fromViewController.view];
        [fromViewController.view removeFromSuperview];
        
        toViewController.view.frame = fromSnapShot.frame;
        [containerView insertSubview:toViewController.view belowSubview:fromSnapShot];

        CGFloat width = floorf(fromSnapShot.frame.size.width/2.0) + 5.0;
        
        [UIView animateKeyframesWithDuration:1.3 delay:0.0 options:0 animations:^{
            [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.2 animations:^{
                CATransform3D fromAni = CATransform3DIdentity;
                fromAni.m34 = 1.0 / -2000;
                fromAni = CATransform3DTranslate(fromAni, 0, 0, -590);
                fromSnapShot.layer.transform = fromAni;
                
                CATransform3D toAni = CATransform3DIdentity;
                toAni.m34 = 1.0 / -2000;
                toAni = CATransform3DTranslate(toAni, 0, 0, -600);
                toViewController.view.layer.transform = toAni;
            }];
            
            [UIView addKeyframeWithRelativeStartTime:0.2 relativeDuration:0.2 animations:^{
                if (self.type == AnimationTypeDismiss) {
                    fromSnapShot.layer.transform = CATransform3DTranslate(fromSnapShot.layer.transform,
                                                                          width, 0.0, 0);
                    toViewController.view.layer.transform = CATransform3DTranslate(toViewController.view.layer.transform, -width, 0.0, 0.0);
                }
            }];
            
            [UIView addKeyframeWithRelativeStartTime:0.4 relativeDuration:0.2 animations:^{
                fromSnapShot.layer.transform = CATransform3DTranslate(fromSnapShot.layer.transform, 0.0, 0.0, -200);
                toViewController.view.layer.transform = CATransform3DTranslate(toViewController.view.layer.transform, 0, 0, 500);
            }];
            
            [UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.2 animations:^{
                CATransform3D fromT = fromSnapShot.layer.transform;
                CATransform3D toT = toViewController.view.layer.transform;
                if (self.type == AnimationTypeDismiss) {
                    fromT = CATransform3DTranslate(fromT, floorf(-width), 0, 200);
                    toT = CATransform3DTranslate(toT, floorf(width * 0.03), 0, 0);
                }
                fromSnapShot.layer.transform = fromT;
                toViewController.view.layer.transform = toT;
            }];
            
            [UIView addKeyframeWithRelativeStartTime:0.80 relativeDuration:0.20 animations:^{
                toViewController.view.layer.transform = CATransform3DIdentity;
                
            }];
        } completion:^(BOOL finished) {
            [_coverButton removeFromSuperview];
            [fromSnapShot removeFromSuperview];
            [transitionContext completeTransition:YES];
        }];
    }

这段代码就比较复杂,首先transitionContext上下文拿到from,to的View,然后一个帧动画,每一个帧又是一个小动画,当然每一个小动画中用到了3DAnimation,这样View不仅会在平面上移动,而且也会在z轴上移动(同时改变View的宽度)。
在第二个试图控制器中给View一个向下的滑动手势后:

- (void)presentedLastViewController {
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

这样就完成上面的动画效果。

你可能感兴趣的:(UIViewController过场动画)