交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)闹炉,提高動(dòng)畫(huà)與用戶交互性郎嫁,從而提升用戶體驗(yàn)奕筐。
通過(guò)手勢(shì)闽颇、重力感覺(jué)等交互操作非凌,使原本連貫的動(dòng)畫(huà)分解呛占,逐漸變化晌姚。
思路:
把原本的動(dòng)畫(huà)的過(guò)渡屿储,抽象成百分比形式(UIPercentDrivenInteractiveTransition協(xié)議實(shí)現(xiàn)原理)鹊奖,與交互操作的變化系數(shù)關(guān)聯(lián)起來(lái)店展。
UIPercentDrivenInteractiveTransition
UIViewControllerInteractiveTransitioning 協(xié)議為我們提供一系列便利的方法养篓,可以通過(guò)一個(gè)百分比控制交互切換的過(guò)程
從系統(tǒng)的api可以看出,交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)兼容iOS7以上
- update(float)
更新動(dòng)畫(huà)進(jìn)度的百分比赂蕴,一般通過(guò)手勢(shì)識(shí)別長(zhǎng)度計(jì)算出的值 - cancel ( )
取消交互柳弄,返回切換前的狀態(tài) - finish ( )
完成交互,更新到切換后的狀態(tài)
demo
【交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)】概说,是建立在【非交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)】的基礎(chǔ)之上
【非交互式】只需要提供present和dismiss的動(dòng)畫(huà)即可
【交互式】則需要在【非交互式】基礎(chǔ)上多提供--交互式動(dòng)畫(huà)控制器
ps: <a href = "http://www.reibang.com/p/4e9ccd0699fb">非交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)</a>碧注,我之前也有文章涉及,這里就不作細(xì)述
新建一個(gè)工具類(lèi)繼承于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)畫(huà)控制器
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)畫(huà)進(jìn)度
func handelOnStagePan(pan:UIPanGestureRecognizer){
let view_transition = pan.translation(in: pan.view!.superview)
//手勢(shì)滑動(dòng)長(zhǎng)度與屏幕寬度的比率,用于控制切換動(dòng)畫(huà)進(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)畫(huà)進(jìn)度
self.update(d)
break
default:
isInteractive = false
if(d > 0.2){
//更新動(dòng)畫(huà)到完成狀態(tài)
self.finish()
}
else {
//返回動(dòng)畫(huà)到切換前的狀態(tài)
self.cancel()
}
break
}
}
//dismiss切換啟動(dòng)手勢(shì)
private var exitPanGesture: UIPanGestureRecognizer!
//dismiss交互動(dòng)畫(huà)控制器
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)畫(huà)進(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)畫(huà)切換控制器(即VC)
2壳影、為VC添加交互手勢(shì)
3、設(shè)置手勢(shì)響應(yīng)方法声怔,判斷手勢(shì)狀態(tài)更新切換進(jìn)度
在MenuTransitionHepler工具類(lèi)最外面态贤,添加 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)此方法),這里就賣(mài)個(gè)關(guān)子醋火,感興趣的童鞋可以看demo源碼
最后在fromVC設(shè)置自定義present的動(dòng)畫(huà)控制器和代理
import UIKit
class fromVC: UIViewController {
//step.5
//初始化自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)協(xié)議對(duì)象
let transitionHelper = MenuTransitionHepler()
override func viewDidLoad() {
super.viewDidLoad()
//step.6
//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的fromVC
self.transitionHelper.sourceViewController=self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//step.7
//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的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悠汽!如果在左邊緣開(kāi)始滑動(dòng)箱吕,效果如下圖:P
總結(jié)
總體來(lái)說(shuō),iOS7后實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)確實(shí)很方便
非交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)柿冲,實(shí)現(xiàn)轉(zhuǎn)場(chǎng)協(xié)議茬高,設(shè)置動(dòng)畫(huà)時(shí)間、動(dòng)畫(huà)邏輯假抄、動(dòng)畫(huà)實(shí)現(xiàn)即可
交互式轉(zhuǎn)場(chǎng)動(dòng)畫(huà)怎栽,則在非交互式的基礎(chǔ)上,多設(shè)置動(dòng)畫(huà)控制器(VC)宿饱、觸發(fā)交互的方法
附帶 <a >Demo</a>傳送門(mén)熏瞄,demo實(shí)現(xiàn)效果比較簡(jiǎn)單,后期也有改成側(cè)滑框架的可能