在iOS开发中,ViewController之间的切换是必不可少的,而系统只提供了Modal、Push、Popover等几种基本的切换方式,往往不能满足我们开发中的需求,最近正好看到了一篇关于这部分动画制作的文章,便决定提炼要点做一下总结,以备不时之需
ViewController之间的切换分为interactive和non-interactive,iOS7当中左划返回就是极好的interactive切换的例子,这里我准备主要讲non-interactive,这种类型用的很多,动画效果也很不错
你要新建一个类,一个animator object,或者是被叫做transition manager,你需要将动画切换过程中的目的ViewController的transitionDelegate设置成你新建的这个类
你新建的这个类至少要满足UIViewControllerTransitioningDelegate 和UIViewControllerAnimatedTransitioning 协议,而UIViewControllerContextTransitioning协议不需要你自己实现,UIViewControllerAnimatedTransitioning协议的代理方法中你就能拿到Context,你只需要在意前两个协议就好了
接下来以一个例子来具体讲一下切换动画的实现过程
一、设置好标准切换方式
ViewController之间的切换一般发生在点击按钮、tableViewCell或者是CollectionViewCell之后,在Storyboard里,你直接按住control拖一条线到你的目的ViewController然后选Present Modally就可以建立Modal方式的ViewController切换,以CollectionViewCell点击切换为例,如下图
二、创建一个右划动画控制类
首先你肯定要NewFile建个类,NSObject的子类就好,然后满足我上面说的前两个协议UIViewControllerTransitioningDelegate 和UIViewControllerAnimatedTransitioning
class SlideDownTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
}
首先来说
UIViewControllerTransitioningDelegate这个协议,这个协议里面有两个方法,分别是:
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
这两个方法分别用来返回切换到目的视图和从目的视图返回时的动画控制器对象,在这里我们返回self,因为不论过去还是回来动画控制器都是我们新建的这个类,当然这两个函数分别是在切换过去和回来的时候调用的,你也可以在return self之前做些事情,比如更改一些标记当前状态的变量的值什么的,用来说明到底是准备过去还是准备回来
接下来我们来说一下UIViewControllerAnimatedTransitioning这个更重要的协议,我们是在这个协议的方法里具体动手制作动画的,你要分别实现这两个方法:
transitionDuration(_:)
animateTransition(_ transitionContext:UIViewControllerContextTransitioning)
第一个方法是描述时长的,返回多少秒就行了,第二个方法是动画产生的地方,当展出和回退的时候这个方法都会被调用来提供具体的动画效果,我们这里要做的动画具体是这样的:
class SlideRightTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
var duration = 0.5
var isPresenting = false
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return duration }
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// Get reference to our fromView, toView and the container view
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
// Set up the transform we'll use in the animation
let container = transitionContext.containerView()
let offScreenLeft = CGAffineTransformMakeTranslation(- container.frame.width, 0)
let offScreenRight = CGAffineTransformMakeTranslation(container.frame.width, 0)
// Make the toView off screen if isPresenting {
toView.transform = offScreenLeft
}
// Add both views to the container view
if isPresenting {
container.addSubview(fromView)
container.addSubview(toView)
} else {
container.addSubview(toView)
container.addSubview(fromView)
}
// Perform the animation
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: nil, animations: {
if self.isPresenting {
toView.transform = CGAffineTransformIdentity
} else {
fromView.transform = offScreenLeft
}
}, completion: { finished in
transitionContext.completeTransition(true) })
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = false
return self }
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = true
return self
}
}
这是具体的实现代码,可以看到第一个方法里我们返回了0.5秒,isPresenting用来表示到底是展出还是回退,offsetScreenRight是向右移动一屏宽的位置,offsetScreenLeft是向左移动一屏宽的位置
如果isPresenting为true,将目的视图放在左侧屏幕外,源视图和目的视图都被放置在了预备位置,即动画的开始位置,也就是这句代码
toView.transform = offScreenLeft
然后将初始视图和目的视图都添加到container中,真正的动画操作在这个函数中
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: nil, animations: {
if self.isPresenting {
toView.transform = CGAffineTransformIdentity
} else {
fromView.transform = offScreenLeft
}
}, completion: {
finished in
transitionContext.completeTransition(true) })
}
目的视图移动到屏幕中心,遮住源视图,完成动画效果