
主界面和菜單之間的循環動畫,正如你在上邊看到的.
每次我看到一個如此優雅的動畫,我就會像每個人想的那樣,我應該怎樣實現他...--等等,難道正常的人不都是這樣想的么?
在這個教程里,你將學會如何使用swift
實現這個酷酷的動畫.在這個過程中,你將學會如果使用shape layers
,masking
,UIViewControllerAnimatedTransitioning協議
和UIPercentDrivenInteractiveTransition類
等等。
注意在這個教程中假設你具備iOS開發基礎。
總體策略
這個動畫發生在你從一個視圖跳轉到另外一個視圖。
在iOS中,你通過使用導航控制器UINavigationController
實現另個視圖控制器間的自定義動畫。你也可以使用iOS7的UIViewControllerAnimatedTransitioning協議
實現過渡動畫效果。?
你必須了解一下細節,其實是這個協議能夠幫你做到
- 指定動畫持續時間
- 創建一個視圖容器關聯兩個視圖控制器
- 實現任何你能夠想象的動畫
你能夠使用這個完成高級復雜的UIView動畫或者簡單低級的Core Animation(在這里,你將實現后者)
實現策略
既然現在你知道了編碼動作在哪里發生,下一點討論的就是如何真真的去實現這個循環過渡動畫
如果你想用自己的話描述這個動畫,大致應該是這樣的:
- 這里有個圓 在視圖的右上方,就像一個按鈕打開了另外一個視圖
- 話句話說,這個圓圈像一個遮罩,它既打開了里面的一切,也會隱藏外面的一切
你可以通過CALayer
的mask
屬性實現這個效果。你也可以通過它的alpha通道來決定這個layer的那一部分能夠被展示

現在你知道了什么是mask,下一步就是決定使用哪一種mask.既然動畫效果是一個原型的遮罩。那自然就應該使用CAShpeLayer
。實現這個圓形動畫,只需要簡單的增加原型遮罩的半徑就OK啦
自定義動畫
注意:省略了前面構建項目,直接專注于動畫創建。具體項目下載
為了寫一個自定義的push
或者 pop
動畫,你需要實現UINavigationControllerDelegate
協議的animationControllerForOperation
方法。
在 iOS\Source\Cocoa Touch Class
創建一個新文件,設置類名為NavigationControllerDelegate
.
創建完文件后,實現該類,如下
class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate {
}
然后設置UINavigationController的代理,回到NavigationControllerDelegate這個類中,添加方法
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
注意這個方法的實現是空的,你待會就會實現它
這個方法接收導航控制器中相互跳轉的兩個視圖控制器,你的任務就是返回一個UIViewControllerAnimatedTransitioning
類
所以你需要創建一個,接著創建一個名為CircleTransitionAnimator
的類(File\New\File)

確定你實現了UIViewControllerAnimatedTransitioning
協議
class CircleTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
下一步就是實現協議需要實現的方法
先加一個下面的方法
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.5
}
在這個方法中,你返回的是動畫的時間。你想讓動畫持續0.5秒。你就返回0.5
接下來給類加一個屬性
weak var transitionContext: UIViewControllerContextTransitioning?
你會在 transition context
中用到它
下面實現第二個方法
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//1
self.transitionContext = transitionContext
//2
let containerView = transitionContext.containerView()
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! ViewController
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as! ViewController
let button = fromViewController.button
//3
containerView!.addSubview(toViewController.view)
//4
let circleMaskPathInitial = UIBezierPath(ovalInRect: button.frame)
let extremePoint = CGPoint(x: button.center.x - 0, y: button.center.y - CGRectGetHeight(toViewController.view.bounds))
let radius = sqrt((extremePoint.x*extremePoint.x) + (extremePoint.y*extremePoint.y))
let circleMaskPathFinal = UIBezierPath(ovalInRect: CGRectInset(button.frame, -radius, -radius))
//5
let maskLayer = CAShapeLayer()
maskLayer.path = circleMaskPathFinal.CGPath
toViewController.view.layer.mask = maskLayer
//6
let maskLayerAnimation = CABasicAnimation(keyPath: "path")
maskLayerAnimation.fromValue = circleMaskPathInitial.CGPath
maskLayerAnimation.toValue = circleMaskPathFinal.CGPath
maskLayerAnimation.duration = self.transitionDuration(transitionContext)
maskLayerAnimation.delegate = self
maskLayer.addAnimation(maskLayerAnimation, forKey: "path")
}
讓我們來一步步分析這些代碼
1.我們先引用transitionContext
這個對象,保證我們在函數的作用域外能夠引用它
2.獲得視圖容器,開始視圖控制器和結束視圖控制器。還有引發事件發生的button.視圖容易是動畫發生的視圖。開始視圖控制器和結束視圖控制器是動畫的參與者。
3.將結束視圖添加到視圖容器中
4.創建兩個圓形的貝塞爾曲線。一個大小和button一樣,另一個有足夠大的半徑覆蓋整個半徑。最終動畫將是這兩個之間的動畫
5.創建一個CAShapeLayer
來展示這個圓形遮罩。將它賦值給結束的圓。避免動畫結束的回彈。
6.創建一個基于貝塞爾曲線的CABasicAnimation
。作用于開始動畫視圖和結束的動畫視圖。同時設置動畫的代理,用來處理動畫結束的一些收尾工作。
下面實現動畫的收尾工作
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
self.transitionContext?.completeTransition(!self.transitionContext!.transitionWasCancelled())
self.transitionContext?.viewControllerForKey(UITransitionContextFromViewControllerKey)?.view.layer.mask = nil
}
下一步就是使用這個動畫效果了,在 NavigationControllerDelegate.swift
中
func navigationController(navigationController: UINavigationController,
animationControllerForOperation operation: UINavigationControllerOperation,
fromViewController fromVC: UIViewController,
toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CircleTransitionAnimator()
}
到此這個酷炫的動畫就實現了,趕緊來試試吧!