閱讀源碼后可以發(fā)現(xiàn)妆丘,和一般自定義轉(zhuǎn)場動畫一致鲜漩,新建繼承 NSObject
子類徘禁,遵守 UIViewControllerAnimatedTransitioning
協(xié)議疾渴。
實(shí)現(xiàn)兩個(gè)代理方法:
- 返回動畫持續(xù)時(shí)間代理:
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.75
}
- 自定義動畫代理:
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// 自定義動畫函數(shù)
}
參數(shù) transitionContext
可以可以通過 func viewForKey(key: String) -> UIView?
/ public func viewControllerForKey(key: String) -> UIViewController?
取出轉(zhuǎn)場動畫的對應(yīng) fromView/toView
/ formViewController/toViewController
對應(yīng)的 key
值:
viewForKey:
UITransitionContextFromViewKey
UITransitionContextToViewKey
viewControllerForKey:
UITransitionContextFromViewControllerKey
UITransitionContextToViewControllerKey
在 Explode
動畫中主要在于屏幕快照的獲取以及快照的區(qū)域分剪,核心代碼:
// 獲取 fromView 的快照
let fromViewSnapshot = fromView.snapshotViewAfterScreenUpdates(false)
// 將快照剪切成小塊加到 containerView 上
for x in 0.0.stride(to: Double(size.width), by: Double(size.width / xFactor)) {
for y in 0.0.stride(to: Double(size.height), by: Double(size.height / yFactor)) {
let snapshotRegion = CGRect(x: CGFloat(x), y: CGFloat(y), width: size.width / xFactor, height: size.height / yFactor)
// 按所給區(qū)域獲得快照的小塊
let snapshot = fromViewSnapshot.resizableSnapshotViewFromRect(snapshotRegion, afterScreenUpdates: false, withCapInsets: UIEdgeInsetsZero)
// 主要是設(shè)置位置
snapshot.frame = snapshotRegion
// 將拼成的 fromView 快照加到 containerView的最頂層
containerView.addSubview(snapshot)
snapshots.append(snapshot)
}
}
// 將 fromView 隱藏
containerView.sendSubviewToBack(fromView)
剩下的就是對 每一個(gè)小塊的動畫處理屯仗,并在動畫結(jié)束后調(diào)用:
ransitionContext.completeTransition(!transitionContext.transitionWasCancelled())
這都很簡單搞坝,難的是如何結(jié)合手勢使用,這是最值得學(xué)習(xí)的地方魁袜,理解不深桩撮,可以 clone 源碼 學(xué)習(xí)敦第。
實(shí)現(xiàn)過程主要是對 UIPercentDrivenInteractiveTransition
的學(xué)習(xí)使用,和 IBAnimatable
的實(shí)現(xiàn)不同店量,我們采用 NavigationController
管理界面芜果,在 FirstViewController
的 func viewWillAppear(animated: Bool) {}
內(nèi)設(shè)置代理: navigationController?.delegate = self
(如果在方法: func viewDidLoad() {}
設(shè)置代理會導(dǎo)致轉(zhuǎn)場取消后無法再次進(jìn)行自定義動畫轉(zhuǎn)場)
實(shí)現(xiàn)代理方法:
extension FirstViewController: UINavigationControllerDelegate {
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == UINavigationControllerOperation.Push {
// ExplodeAnimator 即為自定義的轉(zhuǎn)場動畫
return ExplodeAnimator()
} else {
return nil
}
}
}
之后就是對 SecondViewController
內(nèi)進(jìn)行自定義手勢 popViewController
:
首先對 view
添加返回手勢:
view.addGestureRecognizer({
let pan = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(SecondViewController.pan(_:)))
pan.edges = UIRectEdge.Left
return pan
}())
手勢回調(diào)方法:
func pan(edgePan: UIScreenEdgePanGestureRecognizer) {
let progress = edgePan.translationInView(self.view).x / self.view.bounds.width
if edgePan.state == UIGestureRecognizerState.Began {
self.percentDrivenTransition = UIPercentDrivenInteractiveTransition()
self.navigationController?.popViewControllerAnimated(true)
} else if edgePan.state == UIGestureRecognizerState.Changed {
self.percentDrivenTransition?.updateInteractiveTransition(progress)
} else if edgePan.state == UIGestureRecognizerState.Cancelled || edgePan.state == UIGestureRecognizerState.Ended {
if progress > 0.5 {
self.percentDrivenTransition?.finishInteractiveTransition()
} else {
self.percentDrivenTransition?.cancelInteractiveTransition()
}
self.percentDrivenTransition = nil
}
}
同樣,在 SecondViewController
的 func viewWillAppear(animated: Bool) {}
方法內(nèi)設(shè)置代理: navigationController!.delegate = self
融师,區(qū)別只是在于多實(shí)現(xiàn)一個(gè)代理方法:
extension SecondViewController: UINavigationControllerDelegate {
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == UINavigationControllerOperation.Pop {
return ExplodeAnimator()
} else {
return nil
}
}
func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if animationController is ExplodeAnimator {
return self.percentDrivenTransition
} else {
return nil
}
}
}
大功告成右钾,
效果展示:
![Demo](http://chengluffy.github.io/img/ExplodeDemo.gif)
代碼地址: CodeDemo。
IBAnimatable 源碼的實(shí)現(xiàn)基于高度的封裝旱爆,這也是望塵莫及的地方舀射。