自定义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. 创建动画

实现实际的转场动画

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

     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, presentingController presenting: 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下载(一会补上链接)

时间: 2024-10-09 05:21:05

自定义presentViewController的转场动画(Swift)的相关文章

iOS7教程系列:自定义导航转场动画以及更多

感谢翻译小组成员dingdaojun热心翻译.本篇文章是我们每周推荐优秀国外的技术类文章的其中一篇.如果您有不错的原创或译文,欢迎提交给我们,更欢迎其他朋友加入我们的翻译小组(联系qq:2408167315). 在iOS7以前,开发者如果希望定制导航控制器推入推出视图时的转场动画,一般都只能通过子类化UINavigationController或者自己编写动画代码去覆盖相应的方法,现在iOS7为开发者带来了福音,苹果公司引入了大量新API,给予了开发者很高的自由度,在处理由UIViewContr

【Swift】IOS开发中自定义转场动画

在IOS开发中,我们model另外一个控制器的时候,一般都使用的自定义的转场动画. 其实我们可以自定义一些转场动画.达到不同的转场效果. 步骤如下:(photoBrowser是目标控制器) 1.在源控制器中,设置目标控制器的转场代理为 self 1 //设置Model转场代理 2  photoBrowser.transitioningDelegate = self 2.同时设置目标控制器的model类型 1 //设置Model类型 2 photoBrowser.modalPresentation

swift自定义转场动画(比较有难度)

一 转场效果图和采用转场方式 1 转场效果图 : 2 采用方式 (方法): --> 2.1 自定义转场动画 --> 2.2 协议 二 转场实现需要获取的东西 1 获取转场前图片的frame 2 设置一张临时imageView作为转场图片(图片并不是真实存在的) 3 获取图片放大展示的frame 三 转场图解 四 转场动画思想 1 通过在实现转场动画的类中定义协议方法,定义代理属性,明确谁可以提供需要的frame和imageView,将对方设置为代理,让代理提供需求,达到转场目的. 2 明确代码

iOS自定义转场动画实战讲解

iOS自定义转场动画实战讲解 转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerAnimated:completion:这一组函数以模态视图的方式展现.隐藏视图.如果用到了navigationController,还可以调用pushViewController:animated:和popViewController这一组函数将新的视图控制器压栈.弹栈. 下图中所有转场动画都是自定义的

关于自定义转场动画,我都告诉你。

原文出处: 伯恩的遗产(@翁呀伟呀 ) 概述 这篇文章,我将讲述几种转场动画的自定义方式,并且每种方式附上一个示例,毕竟代码才是我们的语言,这样比较容易上手.其中主要有以下三种自定义方法,供大家参考: Push & Pop Modal Segue 前两种大家都很熟悉,第三种是 Stroyboard 中的拖线,属于 UIStoryboardSegue 类,通过继承这个类来自定义转场过程动画. Push & Pop 首先说一下 Push & Pop 这种转场的自定义,操作步骤如下: 创

自定义转场动画--Swift3.0版本

转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerAnimated:completion:这一组函数以模态视图的方式展现.隐藏视图.如果用到了navigationController,还可以调用pushViewController:animated:和popViewController这一组函数将新的视图控制器压栈.弹栈. 下图中所有转场动画都是自定义的动画,这些效果如果不用自定义动

关于自定义转场动画,我都告诉你

作者:@翁呀伟呀 概述 这篇文章,我将讲述几种转场动画的自定义方式,并且每种方式附上一个示例,毕竟代码才是我们的语言,这样比较容易上手.其中主要有以下三种自定义方法,供大家参考: Push & Pop Modal Segue 前两种大家都很熟悉,第三种是 Stroyboard 中的拖线,属于 UIStoryboardSegue 类,通过继承这个类来自定义转场过程动画. Push & Pop 首先说一下 Push & Pop 这种转场的自定义,操作步骤如下: 1. 创建一个文件继承自

iOS 自定义转场动画篇

前言: 自定义转场动画其实并不难, 关键在于能够明白思路, 也就是操作步骤. 本篇博客主要以present转场动画为例, 进行分析, 操作, 如有错误欢迎简信与我交流. 不进行修改的话, presentViewController:animated:completion:相信这个方法很多人都是用过, 称作模态推出界面, 默认都是从屏幕下方推出新的控制器. 自定义的目的就是为了修改固定的推出方式, 同时加上你想要的动画. 一个关键的概念: UIViewControllerAnimatedTrans

教你实现类似于格瓦拉启动页中的放大转场动画(OC&Swift)

教你实现类似于格瓦拉启动页中的放大转场动画(OC&Swift) 一.前言 用过格瓦拉电影,或者其他app可能都知道,一种点击按钮用放大效果实现转场的动画现在很流行,效果大致如下 在iOS中,在同一个导航控制器你可以自定义转场动画实现两个viewController之间的过渡.实际上在iOS7之后,通过实现UIViewControllerAnimatedTransitioning或者UIViewControllerContextTransitioning协议,就可以简单的自定义转场动画,比如一个N