UIPresentationController自定义转场动画

在APP开发过程中,总要设计到控制器的跳转。在IOS8中,苹果推出了UIPresentationController来管理所有modal的控制器。在这里,我们首选回顾一下,系统自带的modal转场动画效果。modalTransitionStyle分别有已下四种效果:

/*
 UIModalTransitionStyleCoverVertical 默认效果:自下而上
 UIModalTransitionStyleFlipHorizontal 翻转效果
 UIModalTransitionStyleCrossDissolve 淡出效果
 UIModalTransitionStylePartialCurl 上下翻页效果
 */

这个在使用的过程中,仅仅需要修改需要切换控制器的modalTransitionStyle分隔即可。
例如,单击主控制器的跳转到下一个控制器的实现

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

    //初始化要切换的控制器
    UIViewController *vc = [[UIViewController alloc] init];

    //设置其背景颜色
         vc.view.backgroundColor = [UIColor redColor];

         // 设置动画样式(系统自带的调整方式四种)
        vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;

    //控制器跳转
        [self presentViewController:vc animated:YES completion:nil];
}

而到了IOS8以后,苹果推出UIPresentationController可以实现自定义的控制器切换效果,下面我们具体的来学习使用一下。

我们采用一个小demo示例来对其进行演示,首次采用了自动布局的来搭建界面。如下图所示:
效果演示
其中前四个转场效果为苹果系统自带的,如前面讲到的只需要修改modalTransitionStyle的值即可。最后一个效果是自定义转场实现出来的效果,下面我们来进行具体的阐述
在单击了“自定义左右效果”按钮后,需要设置其 设置展示样式为自定义样式

vc.modalPresentationStyle = UIModalPresentationCustom;

除此之外,还需要三个对象来实现自定义过渡,一个UIPresentationController 的子类、一个遵从 UIViewControllerAnimatedTransitioning 协议的类以及遵从UIViewControllerTransitioningDelegate协议的类。

具体代码为:

//在ViewController中点击事件实现:
//要切换的控制器
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    //初始化要切换的控制器
    UIViewController *vc = [[UIViewController alloc] init];

    //设置其背景颜色
    vc.view.backgroundColor = [UIColor redColor];

    //设置展示样式(自定义)
    vc.modalPresentationStyle = UIModalPresentationCustom;

    //设置代理(设置UIPresentationController)(为实现UIViewControllerTransitioningDelegate协议的类)
    vc.transitioningDelegate = [Transition sharedtransition];

    //控制器跳转
    [self presentViewController:vc animated:YES completion:nil];
}

需要自定义转场动画后,需要实现要调整控制器的transitioningDelegate代理。创建实现UIViewControllerTransitioningDelegate协议的类(这里我们命名为Transition (并且将其设置成为单例)),在这个类中实现UIViewControllerTransitioningDelegate协议方法

#pragma mark - UIViewControllerTransitioningDelegate
//设置继承自UIPresentationController 的自定义类的属性
    - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source
    {
        //return 一个UIPresentationController 的子类;
        return [[PresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
    }

    //控制器创建执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        //return 一个 UIViewControllerAnimatedTransitioning 协议的类;
        //创建实现UIViewControllerAnimatedTransitioning协议的类(命名为AnimatedTransitioning)
    AnimatedTransitioning *anim = [[AnimatedTransitioning alloc] init];

    //将其状态改为出现
    anim.presented = YES;
    return anim;
    }

    //控制器销毁执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {

        //return 一个 UIViewControllerAnimatedTransitioning 协议的类;
        //创建实现UIViewControllerAnimatedTransitioning协议的类(命名为AnimatedTransitioning)
    AnimatedTransitioning *anim = [[AnimatedTransitioning alloc] init];

    //将其状态改为出现
    anim.presented = NO;
    return anim;
}

详细信息可以点此查看完整代码
下面首先实现一个 UIPresentationController 的子类(PresentationController)

//即将出现调用
- (void)presentationTransitionWillBegin{
    //添加半透明背景 View 到视图中
    UIView *transtioningView = [[UIView alloc] init];
    transtioningView.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.5];
    self.transtioningView = transtioningView;
    self.transtioningView.frame = self.containerView.bounds;
    self.transtioningView.alpha = 0.0;

    [self.containerView addSubview:self.transtioningView];

    //一旦要自定义动画,必须自己手动添加控制器
    //设置尺寸(在动画中注意调整尺寸)
    self.presentedView.frame = CGRectInset(self.containerView.bounds, 40, 60);
    // 添加到containerView 上
    [self.containerView addSubview:self.presentedView];

    // 与过渡效果一起执行背景 View 的淡入效果
    [[self.presentingViewController transitionCoordinator] animateAlongsideTransitionInView:self.transtioningView animation:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {     
        self.transtioningView.alpha = 1.0;      
    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {      
    }];    
}

//出现调用
- (void)presentationTransitionDidEnd:(BOOL)completed{
    // 如果呈现没有完成,那就移除背景 View
    if (!completed){
        [self.transtioningView removeFromSuperview];
    }
}

//即将销毁调用
- (void)dismissalTransitionWillBegin{
    // 与过渡效果一起执行背景 View 的淡入效果
    [[self.presentingViewController transitionCoordinator] animateAlongsideTransitionInView:self.transtioningView animation:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {

        self.transtioningView.alpha = 0.0;

    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {

    }];
}

//销毁调用
- (void)dismissalTransitionDidEnd:(BOOL)completed{
    if (completed) {
        //一旦要自定义动画,必须自己手动移除控制器
        [self.presentedView removeFromSuperview];

        [self.transtioningView removeFromSuperview];
    }

详细信息可以点此查看完整代码

最后实现一个遵守UIViewControllerAnimatedTransitioning 协议的类(AnimatedTransitioning)
实现方法

#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext{
    //动画执行时间
    return duration;  
}
//实际动画效果(以后需要改的地方只有这里)
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    if (self.presented) {//创建控制器
        UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
        //toView.layer.transform = CATransform3DMakeRotation(M_PI_2, 1, 1, 1);3D动画
        //toView.y = -toView.height;
        toView.x = toView.width;
        [UIView animateWithDuration:duration animations:^{
            //toView.layer.transform = CATransform3DIdentity;3D动画
            //toView.y = 0;
            toView.x = 40;//注意同PresentationController设置的尺寸位置相关
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }else{//销毁控制器
        [UIView animateWithDuration:duration animations:^{
            UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
            //fromView.layer.transform = CATransform3DMakeRotation(M_PI_2, 1, 1, 1);
            //fromView.y = -fromView.height;
            fromView.x = -fromView.width;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];     
        }];
    }   
}

详细信息点此查看完整代码

这样只需要

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

这个方法中修改完成相应的转场动画。

最后对上述步骤进行总结归纳:
第一步:创建需要modal的控制器

UIViewController *vc = [[UIViewController alloc] init];

第二步: 设置展示样式(自定义)

vc.modalPresentationStyle = UIModalPresentationCustom;

第三步:成为其transitioningDelegate的代理

//Transition(单例)为一个实现UIViewControllerTransitioningDelegate协议的类
vc.transitioningDelegate = [Transition sharedtransition];

第四步:modal控制器

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

第五步:实现Transition(单例)类(一个实现了UIViewControllerTransitioningDelegate协议的类)
并实现代理方法

#pragma mark - UIViewControllerTransitioningDelegate
//设置继承自UIPresentationController 的自定义类的属性
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

//控制器创建执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;

    控制器销毁执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;

第六步:根据第五步的代理方法创建一个继承自UIPresentationController 的自定义类,并在其中实现方法下述方法

    //即将出现调用
    - (void)presentationTransitionWillBegin;
    //出现调用
    - (void)presentationTransitionDidEnd:(BOOL)completed;
    //即将销毁调用
    - (void)dismissalTransitionWillBegin;
    //销毁调用
    - (void)dismissalTransitionDidEnd:(BOOL)completed;

第七步:根据第五步的代理方法创建一个实现UIViewControllerAnimatedTransitioning协议的类,并在其中实现下述方法,设置转场动画效果。

    //常量,动画执行的时间
    const CGFloat duration = 1.0;
    #pragma mark - UIViewControllerAnimatedTransitioning
    //动画执行的时间
    - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;   
    //实际动画效果(以后需要改的地方只有这里)
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

按照相应逻辑实现,即可完成自定义转场动画。
最后:一个上述方法实现的小demo已经上传到github上,可以单击此处下载

posted @ 2016-04-01 10:55  zsper  阅读(205)  评论(0编辑  收藏  举报