美文网首页
自定义过渡动画

自定义过渡动画

作者: 轻云绿原 | 来源:发表于2017-03-28 17:29 被阅读35次

    来源

    https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html#//apple_ref/doc/uid/TP40007457-CH16-SW1
    

    过渡动画是把两个controller的内容交换。有两种交换类型:

    1. presentations:加一个新的view controller到你app的 view controller层级。
    2. dismissals:从app里移除一个或多个view controller。

    the transitioning delegate

    transitioning delegate是你自定义呈现和过渡动画的起点。the transitioning delegate是一个你定义的并遵守UIViewControllerTransitioningDelegate协议的对象。它提供给UIKit以下对象:

    1. animator objects:它是创建动画,并用来展示或隐藏一个view controller的view.这个transitioning delegate可以分别提供animator object 给presenting 和dismissing. animator object 遵守UIViewControllerAnimatedTransitioning协议。
    2. interactive animator objects:这个对象可以用事件或手势和驱动自定义动画的时间。它遵守UIViewControllerInteractiveTransitioning协议。
      最简单的创建一个interaction animator 是继承UIPercentDrivenInteractiveTransition 类,并加事件处理代码到你的子类里。这个类控制了你的动画时间(这个动画是用你已存在的animator objects创建的)。如果你要自己创建你自己的interaction animator,你必须自己来渲染动画里的每一帧(还是不要这样做--PPF)。
    3. presentation controller: 当一个view controller展示在屏幕上时, presentation controller管理着展示方式。系统为内置的展示类型提供了presentation controller,并且你也可以为您自己的展示类型提供自定义的presentation controller(这部分在下一篇会讲--PPF)。

    给 view controller的transitioningDelegate属性赋值一个transitioning delegate,用于告诉UIKit 你要执行一个自定义的过渡和展示方式。你的delegate可以选择提供哪个对象。如果你不提供animator objects,UIKit会使用标准的过渡动画,在view controller的modalTransitionStyle的属性里。

    只有当view controller的modalpresentationStype的属性被设为UIModelPresentationCustom时,自定义的presentation controller才会被使用。


    自定义动画的调用顺序。

    当被呈现的view controller的transitioningDelegate属性包含一个有效值时,UIKit就会用你提供的动画对象(animator objects)来呈现那个view controller.当它已经准备好呈现时,UIKit就会调用transition delegate里的 animationControllerForPresentedController:presentingController:sourceController:方法来接收一个动画对象(animator object).如果对象有效,UIKit就会执行以下步骤:

    1. UIKit 会调用transitioning delegate的interactionControllerForPresentation:方法去看一下是否有一个interactive animator(交互动画对象)有效。如果是返回nil,UIKit就会执行一个没有用户交互的动画。
    2. UIKit会调用animator object的 transitionDuration:得到动画持续时间。
    3. UIKit会调用以下一个合适的方法开始动画:
    • 没有interactive animations,UIKit会调用 animator 对象的 animateTransition:。
    • 有interactive animations,UIKit会调用interactive animator对象的 startInteractiveTransition:
    1. UIKit会等着,等着animator对象的context transitioning对象调用 completeTransition: 。
      你自己的自定义的animator会在动画结束后调用这个方法,一般会在动画结束块里(completion block)。调用这个方法来结束过渡,并且让UIKit知道这可以调用presentViewController:animated:completion: 的completion handler(结束块)和调用animator 对象自己的animationEnded:方法。

    当dismissing一个view controller时,UIKit会调用你的transitioning delegate的animationControllerForDismissedController:并执行以下步骤:

    1. UIKit调用transition delegate的interactionControllerForDismissal:方法去看一下是否有一个有效的interactive animator(交互动画对象)。如果是返回nil,UIKit就会执行一个没有用户交互的动画。
    2. UIKit会调用animator object的 transitionDuration:得到动画持续时间。
    3. UIKit会调用以下一个合适的方法开始动画:
      • 没有interactive animations,UIKit会调用 animator 对象的 animateTransition:。
    • 有interactive animations,UIKit会调用interactive animator对象的 startInteractiveTransition:
    1. UIKit会等着,等着animator对象的context transitioning对象调用 completeTransition:
      你自己的自定义的animator会在动画结束后调用这个方法,一般会在动画结束块里(completion block)。调用这个方法来结束过渡,并且让UIKit知道这可以调用presentViewController:animated:completion:的completion handler(结束块)和调用animator 对象自己的animationEnded:方法。
    注意:

    必须在你的动画结束时调用completeTransition:。UIKit不会结束过渡过程,并因此把控制权还给你的app,直到你调用了这个方法。

    The Transitioning Context Object

    注意:

    当你设置自定义的动画时,一定要只使用在transitioning context对象里的对象和数据,而不是你自己管理的缓存数据。过渡是会发生多种多样的情况下,而有一些情况可能会改变动画参数。the transitioning context对象保证会有你需要的正确信息来执行动画,然而你自己的缓存的信息有可能在动画方法被调用时就失效了(不新鲜了)

    Presenting a View Controller Using Custom Animations

    用自定义的动画要呈现一个新的view controller, 在已存在的view controller的活动方法里加以下步聚:

    1. 创建一个你要呈现的view controller.
    2. 创建你自己的transitioning delegate对象,并把它赋给新view controller的transitioningDelegate属性。这个transitioning delegate的方法会在需要的时候提供你自定义的animator对象。
    3. 调用presentViewController:animated:completion:方法,呈现新的view controller。

    试一下

    如果已经有一个segue了,以上的步骤是否可以在prepareForSegue:里进行。

    Getting the Animation Parameters

    • 调用viewControllerForKey:分别得到“from"和”to“两个view controller.
    • 调用containerView方法得到动画的父视图。加入所有的关键subView到这里。比如:加入presented view controller的view。
    • 调用viewForKey:方法得到要加入或移除的view.
    • 调用finalFrameForViewController:方法得到被加入或移除的view的最终frame。

    • from:总是在过渡开始时在屏幕上的view controller.
    • to:总是在过渡结束时在屏幕上的view controller.

    动画的主要目标:

    • presentation:加入”to“view 到container view。
    • dismissal: 从container view里移除”from“view。

    Creating the Transition Animations

    • presentation animations:

    • 使用viewControllerForKey:viewForKey:方法得到view controllers 和views。

    • 设置 "to"view的开始位置。还有其它属性的起始值(比如transform)。

    • finalFrameForViewController:方法得到"to"view的结束位置。

    • 把"to"view作为一个subview加入container view.

    • 创建动画:

    • 在你的动画块里,在container view里把"to"view移动到它的最终位置。设置最终值到它的其它属性里。

    • 在动画结束块里(completion block)里,调用completeTransition:方法,执行其它清理工作。

    • Dismissal animations:

    • 使用viewControllerForKey:viewForKey:方法得到view controllers 和views。

    • 计算"from"view的结束位置。这个presented view controller里的view 现在是要被dismissed。

    • 把"to"view作为一个subview加入container view.
      在过渡结束时,presenting view controller的view("from" view)会被移除。在dismissal过程中,你必须把它加回到container view。

    • 创建动画:

    • 在你的动画块里,在container view里把"from"view移动到它的最终位置。设置最终值到它的其它属性里。

    • 在动画结束块里(completion block)里,移除"from" view,调用completeTransition:方法,执行其它清理工作。

    import UIKit
    
    class PresentationAnimator: NSObject,UIViewControllerAnimatedTransitioning {
        
        // true:presenting   false:dismissable
        let presenting:Bool
        
        init(presenting:Bool) {
            self.presenting = presenting
            super.init()
        }
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 1.5
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            //获取关联的对象
            let containerView = transitionContext.containerView
            let fromVC  = transitionContext.viewController(forKey: .from)!
            let toVC    = transitionContext.viewController(forKey: .to)!
            
            let toV     = transitionContext.view(forKey: .to)!
            let fromV   = transitionContext.view(forKey: .from)!
            
            //设置一些动画的变量。
            let containerFrame = containerView.frame
            
            var toVStartFrame = transitionContext.initialFrame(for: toVC)
            let toVFinalFrame = transitionContext.finalFrame(for: toVC)
            
            var fromVFinalFrame = transitionContext.finalFrame(for: fromVC)
            
            if self.presenting {
                toVStartFrame.origin.x = containerFrame.width
                toVStartFrame.origin.y = containerFrame.height
    
                containerView.addSubview(toV)
                toV.frame = toVStartFrame
            }else{
                fromVFinalFrame.origin.x = containerFrame.width
                fromVFinalFrame.origin.y = containerFrame.height
                fromVFinalFrame.size.width = toV.frame.size.width
                fromVFinalFrame.size.height = toV.frame.size.height
    
                containerView.insertSubview(toV, at: 0)
                toV.frame = toVFinalFrame
            }
            
            
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { 
                if self.presenting{
                    toV.frame = toVFinalFrame
                }else{
                    fromV.frame = fromVFinalFrame
                }
            }) { (_) in
                let success = !transitionContext.transitionWasCancelled
                // After a failed presentation or successful dismissal, remove the view.
                if (self.presenting && !success) || (!self.presenting && success){
                    toV.removeFromSuperview()
                }
                transitionContext.completeTransition(success)
            }
        }
    }
    

    中间还有一段interface animator 等以后再看看........


    以上的东西也可以用在navigation controller上。push pop.

    self.navigationController?.delegate = self
    let percentDriven =  UIPercentDrivenInteractiveTransition()
    
    extension ViewController:UINavigationControllerDelegate{
        func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            switch operation {
            case .push:
                //animator object
                return PresentationAnimator(presenting: true)
            case .pop:
                return PresentationAnimator(presenting: false)
            default:
                return nil
            }
        }
    }
    
        func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            return percentDriven;
        }
    
    

    相关文章

      网友评论

          本文标题:自定义过渡动画

          本文链接:https://www.haomeiwen.com/subject/ornjottx.html