自定义presentViewController的转场动画(Swift)

前端之家收集整理的这篇文章主要介绍了自定义presentViewController的转场动画(Swift)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

原创Blog,转载请注明出处

我的StackFlow


前言:

iOS默认的presentViewController的切换动画是从底部推入,消失是从顶部推出。但是,因为iOS系统默认的是适配所有转场上下文的。而针对特定的转场上下文,我们能做出更好的效果

Tips:所谓的转场上下文,就是转场的开始View和结束View,以及对应的ViewController


目标效果

最终的效果


准备工作

首先写出一个CollectionView,每个Cell是一个图片,由于本文的核心是如何转场,所以CollectionView的部分略过。写完了之后,是这样的效果

点击某一个CollectionView Cell查看大图,再点击大图图片消失

这个最初的项目,可以在这里下载

CSDN下载


如何实现自定义转场动画

iOS 8之后,我们可以通过设置ViewControllertransitioningDelegate来设置代理来处理转场动画。

通过文档,可以看到transitioningDelegate是一个实现UIViewControllerTransitioningDelegate协议的对象,先看看这个协议,本文主要利用以下两个方法

  • animationControllerForDismissedController
  • animationControllerForPresentedController

着两个方法的目的是,提供一个遵循UIViewControllerAnimatedTransitioning协议的对象,然后又这个对象来实际处理专场。通过名字就可以看出来,一个是处理present一个是处理dismiss。

本文的设计是让ViewController来处理转场,在didSelectItemAtIndexPath中,设置pvc的转场代理

dvc.transitioningDelegate = self

然后,写一个extension来实现协议

extension ViewController:UIViewControllerTransitioningDelegate{
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil
    }
    func animationControllerForPresentedController(presented: UIViewController,presentingController presenting: UIViewController,sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil
    }
}

这时候,再运行项目,会发现没有任何变化,还是默认的转场方式。因为我们还没有提供实际的动画 。当上述两个代理方法返回nil的时候,系统会使用默认的方式


实现UIViewControllerAnimatedTransitioning

新建一个文件,命名为Animator.swift,然后新建一个类,处理Present的转场(Dismiss类似),实现UIViewControllerAnimatedTransitioning协议

class PresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{

这时候,会报错没有实现协议,然后,我们添加协议方法,这时候的Animator.swift如下

import Foundation
import UIKit

class PresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{
    let duration = 0.5 //动画的时间
    var originFrame = CGRectZero //点击Cell的frame
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return duration
    }
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    }
}

简单介绍下这里的协议方法

  • transitionDuration,返回转场动画的时间
  • animateTransition,进行实际的转场动画,通过参数transitionContext(转场上下文)来获取转场的fromView,toView,fromViewController,toViewController。

转场的原理

  • 转场开始的时候,自动把FromView添加到转场ContainView
  • 转场结束的时候,自动把FromView移除ContainView

所以,开发者要做的就是

  1. 把toView添加到转场ContainView中,并且定义好toView的初始位置和状态
  2. 定义好FromView和ToView的转场结束时候的状态
  3. 创建动画
  4. @H_502_194@

    实现实际的转场动画

    基于上述的原理,我们修改实际的动画

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            let containView = transitionContext.containerView()
            let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
    
            let finalFrame = toView.frame
    
            let xScale = originFrame.size.width/toView.frame.size.width
            let yScale = originFrame.size.height/toView.frame.size.height
            toView.transform = CGAffineTransformMakeScale(xScale,yScale)
            toView.center = CGPointMake(CGRectGetMidX(originFrame),CGRectGetMidY(originFrame))
    
            containView?.addSubview(toView)
            UIView.animateWithDuration(duration,animations: { () -> Void in
                toView.center = CGPointMake(CGRectGetMidX(finalFrame),CGRectGetMidY(finalFrame))
                toView.transform = CGAffineTransformIdentity
                }) { (finished) -> Void in
                    transitionContext.completeTransition(true)
            }
        }

    然后,在ViewController.swfit中,添加属性

    let presentAnimator = PresentAnimator()

    修改didSelectItemAtIndexPath

    override func collectionView(collectionView: UICollectionView,didSelectItemAtIndexPath indexPath: NSIndexPath) {
            let dvc = DetailViewController()
            dvc.image = UIImage(named: "image.jpg")
            dvc.transitioningDelegate = self
            let cell =  collectionView.cellForItemAtIndexPath(indexPath) as! FullImageCell
            presentAnimator.originFrame = cell.convertRect(cell.imageview.frame,toView: nil)
            self.presentViewController(dvc,animated: true,completion: nil)
        }

    修改代理方法

    func animationControllerForPresentedController(presented: UIViewController,sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return presentAnimator
        }

    这时候的动画效果如Gif


    同理,为dismiss添加转场动画

    在Animator.swift中添加一个新的类

    class DismisssAnimator:NSObject,UIViewControllerAnimatedTransitioning{
        let duration = 0.6
        var originFrame = CGRectZero
        func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
            return duration
        }
        func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            let containView = transitionContext.containerView()
            let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! //Collection View
            let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! //全屏的imageview
            let xScale = originFrame.size.width/toView.frame.size.width
            let yScale = originFrame.size.height/toView.frame.size.height
            containView?.addSubview(toView)
            containView?.bringSubviewToFront(fromView)
            UIView.animateWithDuration(duration,animations: { () -> Void in
                fromView.center = CGPointMake(CGRectGetMidX(self.originFrame),CGRectGetMidY(self.originFrame))
                fromView.transform = CGAffineTransformMakeScale(xScale,yScale)
                }) { (finished) -> Void in
                    transitionContext.completeTransition(true)
            }
        }
    }

    然后,在ViewController.swift中didSelectItemAtIndexPath设置presentAnimator.frame下一行添加

    dismissAnimator.originFrame = cell.convertRect(cell.imageview.frame,toView: nil)

    其中,dismissAnimator是ViewController的一个属性

    let dismissAnimator = DismisssAnimator()

    然后,在代理方法中,返回

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return dismissAnimator;
        }

    最终的效果


    完整工程的下载

    CSDN下载

原文链接:https://www.f2er.com/swift/324036.html

猜你在找的Swift相关文章