交互式轉(zhuǎn)場(chǎng)動(dòng)畫
交互式轉(zhuǎn)場(chǎng)動(dòng)畫,提高動(dòng)畫與用戶交互性,從而提升用戶體驗(yàn)。
通過手勢(shì)、重力感覺等交互操作,使原本連貫的動(dòng)畫分解,逐漸變化。
思路:
把原本的動(dòng)畫的過渡,抽象成百分比形式(UIPercentDrivenInteractiveTransition協(xié)議實(shí)現(xiàn)原理),與交互操作的變化系數(shù)關(guān)聯(lián)起來(lái)。
UIPercentDrivenInteractiveTransition
UIViewControllerInteractiveTransitioning 協(xié)議為我們提供一系列便利的方法,可以通過一個(gè)百分比控制交互切換的過程


從系統(tǒng)的api可以看出,交互式轉(zhuǎn)場(chǎng)動(dòng)畫兼容iOS7以上
- update(float)
更新動(dòng)畫進(jìn)度的百分比,一般通過手勢(shì)識(shí)別長(zhǎng)度計(jì)算出的值 - cancel ( )
取消交互,返回切換前的狀態(tài) - finish ( )
完成交互,更新到切換后的狀態(tài)
demo
【交互式轉(zhuǎn)場(chǎng)動(dòng)畫】,是建立在【非交互式轉(zhuǎn)場(chǎng)動(dòng)畫】的基礎(chǔ)之上
【非交互式】只需要提供present和dismiss的動(dòng)畫即可
【交互式】則需要在【非交互式】基礎(chǔ)上多提供--交互式動(dòng)畫控制器
ps: <a href = "http://www.itdecent.cn/p/4e9ccd0699fb">非交互式轉(zhuǎn)場(chǎng)動(dòng)畫</a>,我之前也有文章涉及,這里就不作細(xì)述
新建一個(gè)工具類繼承于UIPercentDrivenInteractiveTransition,實(shí)現(xiàn)交互切換的協(xié)議
import UIKit
//判斷是【交互式】還是【非交互式】
private var isInteractive = false
//判斷是presented還是dismiss
private var isPresenting = false
class MenuTransitionHepler: UIPercentDrivenInteractiveTransition,UIViewControllerAnimatedTransitioning,UIViewControllerTransitioningDelegate {
//step.4
//實(shí)現(xiàn)UIPercentDrivenInteractiveTransition交互切換協(xié)議
//present切換啟動(dòng)手勢(shì)
private var enterPanGesture: UIScreenEdgePanGestureRecognizer!
//present交互動(dòng)畫控制器
var sourceViewController : UIViewController! {
didSet{
self.enterPanGesture = UIScreenEdgePanGestureRecognizer()
self.enterPanGesture.addTarget(self, action: #selector(MenuTransitionHepler.handelOnStagePan(pan:)))
self.enterPanGesture.edges=UIRectEdge.left
self.sourceViewController.view.addGestureRecognizer(self.enterPanGesture)
}
}
//present手勢(shì)長(zhǎng)度比率,控制動(dòng)畫進(jìn)度
func handelOnStagePan(pan:UIPanGestureRecognizer){
let view_transition = pan.translation(in: pan.view!.superview)
//手勢(shì)滑動(dòng)長(zhǎng)度與屏幕寬度的比率,用于控制切換動(dòng)畫進(jìn)度
let d = view_transition.x / (pan.view?.bounds.width)! * 0.5
print(d)
switch pan.state {
case UIGestureRecognizerState.began:
isInteractive=true
//調(diào)用fromVC調(diào)用present方法,此方法是storyboard的線跳
self.sourceViewController.performSegue(withIdentifier: "presentMenu", sender: self)
break
case UIGestureRecognizerState.changed:
//更新切換動(dòng)畫進(jìn)度
self.update(d)
break
default:
isInteractive = false
if(d > 0.2){
//更新動(dòng)畫到完成狀態(tài)
self.finish()
}
else {
//返回動(dòng)畫到切換前的狀態(tài)
self.cancel()
}
break
}
}
//dismiss切換啟動(dòng)手勢(shì)
private var exitPanGesture: UIPanGestureRecognizer!
//dismiss交互動(dòng)畫控制器
var menuViewController: UIViewController! {
didSet {
self.exitPanGesture = UIPanGestureRecognizer()
self.exitPanGesture.addTarget(self, action:#selector(MenuTransitionHepler.handleOffstagePan(pan:)))
self.menuViewController.view.addGestureRecognizer(self.exitPanGesture)
}
}
//dismiss手勢(shì)長(zhǎng)度比率,控制動(dòng)畫進(jìn)度
func handleOffstagePan(pan: UIPanGestureRecognizer){
let view_transition = pan.translation(in: pan.view!)
let d = view_transition.x / (pan.view?.bounds.width)! * -0.5
switch pan.state {
case UIGestureRecognizerState.began:
isInteractive=true
self.menuViewController.dismiss(animated: true, completion: nil)
break
case UIGestureRecognizerState.changed:
self.update(d)
break
default:
isInteractive = false
if(d > 0.1){
self.finish()
}
else {
self.cancel()
}
break
}
}
}
上述代碼中,主要實(shí)現(xiàn)幾個(gè)功能:
1、添加present和dismiss的動(dòng)畫切換控制器(即VC)
2、為VC添加交互手勢(shì)
3、設(shè)置手勢(shì)響應(yīng)方法,判斷手勢(shì)狀態(tài)更新切換進(jìn)度
在MenuTransitionHepler工具類最外面,添加 UIViewControllerTransitioningDelegate的實(shí)現(xiàn)方法
//step.1
//UIViewControllerTransitioningDelegate代理方法
extension MenuTransitionHepler{
//presented
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting=true
return self
}
//dismissed
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting=false
return self
}
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return isInteractive ? self : nil
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return isInteractive ? self : nil
}
}
接下來(lái)就是實(shí)現(xiàn)非交互切換的方法(交互式切換需要實(shí)現(xiàn)此方法),這里就賣個(gè)關(guān)子,感興趣的童鞋可以看demo源碼
最后在fromVC設(shè)置自定義present的動(dòng)畫控制器和代理
import UIKit
class fromVC: UIViewController {
//step.5
//初始化自定義轉(zhuǎn)場(chǎng)動(dòng)畫協(xié)議對(duì)象
let transitionHelper = MenuTransitionHepler()
override func viewDidLoad() {
super.viewDidLoad()
//step.6
//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫的fromVC
self.transitionHelper.sourceViewController=self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//step.7
//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫的toVC
let menu = segue.destination as! MenuVC
//step.8
//設(shè)置transitioningDelegate為【自定義轉(zhuǎn)場(chǎng)協(xié)議】
menu.transitioningDelegate = self.transitionHelper
self.transitionHelper.menuViewController = menu
}
}
finish!如果在左邊緣開始滑動(dòng),效果如下圖:P

總結(jié)
總體來(lái)說,iOS7后實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫確實(shí)很方便
非交互式轉(zhuǎn)場(chǎng)動(dòng)畫,實(shí)現(xiàn)轉(zhuǎn)場(chǎng)協(xié)議,設(shè)置動(dòng)畫時(shí)間、動(dòng)畫邏輯、動(dòng)畫實(shí)現(xiàn)即可
交互式轉(zhuǎn)場(chǎng)動(dòng)畫,則在非交互式的基礎(chǔ)上,多設(shè)置動(dòng)畫控制器(VC)、觸發(fā)交互的方法
附帶 <a >Demo</a>傳送門,demo實(shí)現(xiàn)效果比較簡(jiǎn)單,后期也有改成側(cè)滑框架的可能