iOS 自定义VC切换动画

在有些情况下,系统自带的导航的push动画无法满足我们APP的设计需求,我们需要自定义VC的转场动画,下面是我参照别人博客,写的一个一个自定义转场动画.

(一) push
这里有一个push的自定义动画:

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    self.navigationController.delegate = self;
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}

- (id)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController *)fromVC
                                                 toViewController:(UIViewController *)toVC {
    if (fromVC == self && [toVC isKindOfClass:[SecondViewController class]]) {
        return [[FirstTransition alloc] init];
    }
    else {
        return nil;
    }
}

这里需要实现导航的代理,实现导航的代理方法.其中,

FirstTransition 

是自己定义的一个动画效果,具体代码如下:

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

- (void)animateTransition:(id)transitionContext {
    
    FirstViewController *fromViewController = (FirstViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    SecondViewController *toViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    UIView *containerView = [transitionContext containerView];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    
    //设置初始view的状态
    NSLog(@"frame = %@",NSStringFromCGRect([transitionContext finalFrameForViewController:toViewController]));
    toViewController.view.frame = CGRectMake(0, 667, 375, 667);
    
    [containerView addSubview:toViewController.view];
    
    [UIView animateWithDuration:duration animations:^{
        toViewController.view.frame = CGRectMake(0, 0, 375, 667);
        fromViewController.view.frame = CGRectMake(0, -667, 375, 667);
    }completion:^(BOOL finished) {
        
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];
}

其中,

    UIView *containerView = [transitionContext containerView];

类似动画的画布,这里可以处理我们需要设置的一些坐标类等参数.这里我做的是一个向上推出的动画效果.

(二) pop
同样的,先上代码:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    self.navigationController.delegate = self;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}

-(id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
    if (fromVC == self && [toVC isKindOfClass:[FirstViewController class]]) {
        return [[SecondTransition alloc] init];
    }
    return nil;
}

-(id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController{
    if ([animationController isKindOfClass:[SecondTransition class]]) {
        return self.interactivePopTransition;
    }
    return nil;
}

-(void)handlePopRecognizer:(UIScreenEdgePanGestureRecognizer*)recognizer{
    //计算用户拖动距离
    CGFloat progress = [recognizer translationInView:self.view].x / (self.view.bounds.size.width * 1.0);
    progress = MIN(1.0, MAX(0.0, progress));
    
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
        [self.navigationController popViewControllerAnimated:YES];
    }
    else if(recognizer.state == UIGestureRecognizerStateChanged){
        [self.interactivePopTransition updateInteractiveTransition:progress];
    }
    else if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled){
        if (progress > 0.5) {
            [self.interactivePopTransition finishInteractiveTransition];
        }else{
            [self.interactivePopTransition cancelInteractiveTransition];
        }
        
        self.interactivePopTransition = nil;
    }
}

这里的 self.interactivePopTransition的是UIPercentDrivenInteractiveTransition的实例,关于UIPercentDrivenInteractiveTransition,这里有篇详细介绍:
https://onevcat.com/2013/10/vc-transition-in-ios7/
这样可以根据手势来控制动画的进行程度,因为这里我写的是与pop相反的动画效果.

SecondTransition

里面的代码如下:


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

-(void)animateTransition:(id)transitionContext{
    // 获取两个互相切换的VC
    SecondViewController *fromViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    FirstViewController *toViewController = (FirstViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // 获得画布及动画时间
    UIView *containerView = [transitionContext containerView];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    //设置初始view的状态
    [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
    [UIView animateWithDuration:duration animations:^{
        fromViewController.view.alpha = 1.0;
        toViewController.view.frame = CGRectMake(0, 0, 375, 667);
        fromViewController.view.frame = CGRectMake(0, 667, 375, 667);
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];
}

对应的手势为:

    UIScreenEdgePanGestureRecognizer *popRegognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];
    popRegognizer.edges = UIRectEdgeLeft;
    [self.view addGestureRecognizer:popRegognizer];

以上代码均来自他人博客,只有动画是我自己写到的,只为自己查询方便,见谅.

你可能感兴趣的:(iOS 自定义VC切换动画)