iOS 利用UIPresentationController自定义转场动画

1. 系统默认modal出来的动画效果默认是从屏幕底部爬出来的

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    secondVC *second = [[secondVC alloc] init];

  [self presentViewController:second animated:YES completion:nil];

}

2. 想自定义转场动画,首先设置 展示样式过渡代理

    secondVC *second = [[secondVC alloc] init];

    second.modalPresentationStyle = UIModalPresentationCustom;

    second.transitioningDelegate = self;

    [self presentViewController:second animated:YES completion:nil];

3.实现过渡代理方法,告诉程序" 哪个对象管理控制器的展示 "

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source

{

    return [[MYPresentationController alloc]initWithPresentedViewController:presented presentingViewController:presenting];

}

4.自定义UIPresentationController

// MYPresentationController.h

@interface MYPresentationController : UIPresentationController

@end

// MYPresentationController.m

#import "MYPresentationController.h"

@implementation MYPresentationController

- (CGRect)frameOfPresentedViewInContainerView

{  

  return CGRectMake(100, 100, 150, 300); //设置modal出来控制器的frame

}

// 下面这几个方法,监听Modal控制器时的各种状态

- (void)presentationTransitionWillBegin

{

    NSLog(@"presentationTransitionWillBegin"); 

}

- (void)presentationTransitionDidEnd:(BOOL)completed

{

    NSLog(@"presentationTransitionDidEnd");

}

- (void)dismissalTransitionWillBegin

{

    NSLog(@"presentationTransitionDidEnd");

}

- (void)dismissalTransitionDidEnd:(BOOL)completed

{

    NSLog(@"dismissalTransitionDidEnd");

}

@end

5. 到了第4步,也只是做到了自定义展示,可以监听展示的过程,可以设置展示的frame.

  要想实现自定义转场动画,可以考虑设置second.modalTransitionStyle,但是没有UIModalTransitionStyleCustom,是因为

    只要设置了UIModalPresentationCustom,也就相当于设置了"UIModalTransitionStyleCustom",要想实现自定义转场动画,只要实现相应的代理方法即可

    secondVC *second = [[secondVC alloc] init];

    second.modalPresentationStyle = UIModalPresentationCustom;

    second.transitioningDelegate = self;

  second.modalTransitionStyle = UIModalTransitionStyleCoverVertical; // 要实现自定义转场动画,不是在这里设置

    [self presentViewController:second animated:YES completion:nil];

#pragma mark - 自定义转场动画的代理方法,两个,分别控制显示和消失

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source

{

    return self; // 简单处理,返回self,只要self遵守<UIViewControllerAnimatedTransitioning>协议

}

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

{

    return self;

}

6.实现<UIViewControllerAnimatedTransitioning>协议方法,下面两个协议方法是必须实现的

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext{

    return 0.3;

}

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

    UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];

        toView.y = -toView.height;

        [UIView animateWithDuration:0.3 animations:^{

            toView.y = 0;

        } completion:^(BOOL finished) {

            [transitionContext completeTransition:YES]; //这个必须写,否则程序 认为动画还在执行中,会导致展示完界面后,无法处理用户的点击事件

        }];

}

这样就实现了modal出来的控制器,是从屏幕顶部下来的转场动画

7. 要实现 控制器消失时的动画,怎么办

7.1 新增一个类,该类遵守<UIViewControllerAnimatedTransitioning>,新增一个属性,用来区别 显示或消失

// MYAnimatedTransition.h

@interface MYAnimatedTransition : NSObject<UIViewControllerAnimatedTransitioning>

@property (assign,nonatomic) BOOL show;

@end

// MYAnimatedTransition.m

@implementation MYAnimatedTransition

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext

{

    return 0.3;

}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext

{

    if (self.show == YES) { // 显示  

        UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];

        toView.y = -toView.height;

        [UIView animateWithDuration:0.3 animations:^{

            toView.y = 0;

        } completion:^(BOOL finished) {

            [transitionContext completeTransition:YES];

        }];    

    }else{  // 消失      

        UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];

        [UIView animateWithDuration:0.3 animations:^{

            fromView.y = fromView.height;

        } completion:^(BOOL finished) {

            [transitionContext completeTransition:YES];

        }];

    }

}

@end

7.2 修改自定义转场动画的代理方法,返回MYAnimatedTransition类对象

#pragma mark - 自定义转场动画的代理方法,两个,分别控制显示和消失

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source

{

    MYAnimatedTransition *anima = [[MYAnimatedTransition alloc]init];

    anima.show = YES;

    return anima;

}

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

{

    MYAnimatedTransition *anima = [[MYAnimatedTransition alloc]init];

    anima.show = NO;

    return anima;

}

7.3 修改自定义UIPresentationController的.m文件

- (void)presentationTransitionWillBegin{

    NSLog(@"presentationTransitionWillBegin");

    [self.containerView addSubview:self.presentedView]; // 因为是自定义转场动画,所以添加视图的工作也需要自行实现

}

- (void)dismissalTransitionDidEnd:(BOOL)completed

{

    NSLog(@"dismissalTransitionDidEnd");

    [self.presentedView removeFromSuperview]; // 因为是自定义转场动画,所以移除视图的工作也需要自行实现

}

而且下面这个方法作废了,程序是不会执行的,因为你是自定义转场动画,动画前后的Frame都已经在这个方法实现了: - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext

- (CGRect)frameOfPresentedViewInContainerView

{  

  return CGRectMake(100, 100, 150, 300); 

}

7.4 要实现更复杂的转场动画,只要改下面这个方法,比如改成3D旋转

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext

{

        UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];

        // toView.y = -toView.height;

        toView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);

        [UIView animateWithDuration:0.3 animations:^{

            // toView.y = 0;

            toView.layer.transform = CATransform3DIdentity;

        } completion:^(BOOL finished) {

            [transitionContext completeTransition:YES];

        }];

        

    }else{

        

        UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];

        [UIView animateWithDuration:0.3 animations:^{

               // fromView.y = fromView.height;

               fromView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);

        } completion:^(BOOL finished) {

            [transitionContext completeTransition:YES];

        }];

    }

}

原文地址:https://www.cnblogs.com/oumygade/p/4280512.html