iOS開發中ViewController切換動畫的製作
阿新 • • 發佈:2019-02-01
在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
首先來說UIViewControllerTransitioningDelegate這個協議,這個協議裡面有兩個方法,分別是:
這兩個方法分別用來返回切換到目的檢視和從目的檢視返回時的動畫控制器物件,在這裡我們返回self,因為不論過去還是回來動畫控制器都是我們新建的這個類,當然這兩個函式分別是在切換過去和回來的時候呼叫的,你也可以在return self之前做些事情,比如更改一些標記當前狀態的變數的值什麼的,用來說明到底是準備過去還是準備回來 接下來我們來說一下UIViewControllerAnimatedTransitioning這個更重要的協議,我們是在這個協議的方法裡具體動手製作動畫的,你要分別實現這兩個方法:
第一個方法是描述時長的,返回多少秒就行了,第二個方法是動畫產生的地方,當展出和回退的時候這個方法都會被呼叫來提供具體的動畫效果,我們這裡要做的動畫具體是這樣的:
這是具體的實現程式碼,可以看到第一個方法裡我們返回了0.5秒,isPresenting用來表示到底是展出還是回退,offsetScreenRight是向右移動一屏寬的位置,offsetScreenLeft是向左移動一屏寬的位置 如果isPresenting為true,將目的檢視放在左側螢幕外,源檢視和目的檢視都被放置在了預備位置,即動畫的開始位置,也就是這句程式碼
然後將初始檢視和目的檢視都新增到container中,真正的動畫操作在這個函式中
目的檢視移動到螢幕中心,遮住源檢視,完成動畫效果
二、建立一個右划動畫控制類 首先你肯定要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) })
}
目的檢視移動到螢幕中心,遮住源檢視,完成動畫效果