zoukankan      html  css  js  c++  java
  • 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上,可以单击此处下载

    不积跬步,无以至千里;不积小流,无以成江海。
  • 相关阅读:
    k8s集群中遇到etcd集群故障的排查思路
    keepalived安装
    python读取文件特定的行数
    Pycharm 退回跳转之前光标页面位置
    python中yield的用法详解——最简单,最清晰的解释
    np.random.permutation()解析
    处理文本分类数据集——THUCNews数据
    [深度学习] PyTorch 实现双向LSTM 情感分析
    lstm模型与情感分析实例
    跑Bert还得用tensorflow-1.11.0版本,否则报错
  • 原文地址:https://www.cnblogs.com/xiaocai-ios/p/7779808.html
Copyright © 2011-2022 走看看