欢迎来到 IT实训基地-南通科迅教育
咨询电话:0513-81107100
自定义presentViewController的转场动画(Swift)
2016/11/10
科迅教育
381
南通网页设计培训学校哪家好-可免费试听

前言:

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

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


目标效果

最终的效果


准备工作

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

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



 


如何实现自定义转场动画

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

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

animationControllerForDismissedController animationControllerForPresentedController

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

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

?
1
<codeclass="hljs fix">dvc.transitioningDelegate = self</code>

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

?
1
2
3
4
5
6
7
8
<codeclass="hljs objectivec">extension ViewController:UIViewControllerTransitioningDelegate{
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        returnnil
    }
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        returnnil
    }
}</code>

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


实现UIViewControllerAnimatedTransitioning

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

?
1
2
<codeclass="hljs ruby">classPresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{
}</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<codeclass="hljs lasso">importFoundation
importUIKit
 
classPresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{
    let duration =0.5//动画的时间
    var originFrame = CGRectZero//点击Cell的frame
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        returnduration
    }
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
 
    }
}
</code>

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

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

转场的原理


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

所以,开发者要做的就是

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

实现实际的转场动画

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<codeclass="hljs avrasm">     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)
        }
    }</code>

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

?
1
2
<codeclass="hljs bash">    let presentAnimator = PresentAnimator()
</code>

修改didSelectItemAtIndexPath

?
1
2
3
4
5
6
7
8
<codeclass="hljs avrasm">    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)
    }</code>

修改代理方法

?
1
2
3
<codeclass="hljs objectivec">    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        returnpresentAnimator
    }</code>

这时候的动画效果如Gif



同理,为dismiss添加转场动画

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<codeclass="hljs avrasm">classDismisssAnimator:NSObject,UIViewControllerAnimatedTransitioning{
    let duration =0.6
    var originFrame = CGRectZero
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        returnduration
    }
    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)
        }
    }
}</code>

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

?
1
2
<codeclass="hljs avrasm"> dismissAnimator.originFrame = cell.convertRect(cell.imageview.frame, toView: nil)
</code>

其中,dismissAnimator是ViewController的一个属性

?
1
<codeclass="hljs bash">    let dismissAnimator = DismisssAnimator()</code>

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

?
1
2
3
<codeclass="hljs coffeescript"> func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        returndismissAnimator;
    }</code>

最终的效果

77
关闭
先学习,后交费申请表
每期5位名额
在线咨询
免费电话
QQ联系
先学习,后交费
TOP
您好,您想咨询哪门课程呢?
关于我们
机构简介
官方资讯
地理位置
联系我们
0513-91107100
周一至周六     8:30-21:00
微信扫我送教程
手机端访问
南通科迅教育信息咨询有限公司     苏ICP备15009282号     联系地址:江苏省南通市人民中路23-6号新亚大厦三楼             法律顾问:江苏瑞慈律师事务所     Copyright 2008-