2017-09-04 46 views
0

我分類爲UINavigationController,並創建了一個處理推送和彈出轉換的非交互式動畫對象。要完成此操作,我如何添加​​來處理下面的自定義流行動畫?我有點困惑從哪裏去,所以任何幫助將是偉大的,謝謝!如何添加屏幕邊緣平移手勢識別器來處理此流行動畫?

class CustomNavigationController: UINavigationController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     delegate = self 
     isNavigationBarHidden = true 

    } 

} 

extension CustomNavigationController: UINavigationControllerDelegate { 

    // noninteractive animator objects 
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 

     switch operation { 

     case .push: 
      return CustomPushAnimator() 

     case .pop: 
      return CustomPopAnimator() 

     default: 
      return nil 

     } 

    } 

    // the interactive animator controller 
    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 

     switch animationController { 

     case is CustomPopAnimator: 
      return CustomInteractiveController() 

     default: 
      return nil 

    } 

} 

// the noninteractive push animator 
class CustomPushAnimator: NSObject, UIViewControllerAnimatedTransitioning { 

    // push transition duration 
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 

     return 0.2 

    } 

    // push transition animation 
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 

     let viewWidth = UIScreen.main.bounds.width 
     let viewHeight = UIScreen.main.bounds.height 
     let containerView = transitionContext.containerView 
     let toViewController = transitionContext.viewController(forKey: .to) 

     containerView.addSubview((toViewController?.view)!) 
     toViewController?.view.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: viewHeight) 

     UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: { 
      toViewController?.view.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) 
     }, completion: { finished in 
      transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 
     }) 

    } 

} 

// the noninteractive pop animator 
class CustomPopAnimator: NSObject, UIViewControllerAnimatedTransitioning { 

    // pop transition duration 
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 

     return 0.2 

    } 

    // pop transition animation 
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 

     let viewWidth = UIScreen.main.bounds.width 
     let viewHeight = UIScreen.main.bounds.height 
     let containerView = transitionContext.containerView 
     let fromViewController = transitionContext.viewController(forKey: .from) 
     let toViewController = transitionContext.viewController(forKey: .to) 

     containerView.insertSubview((toViewController?.view)!, belowSubview: (fromViewController?.view)!) 

     UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: { 
      fromViewController?.view.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: viewHeight) 
     }, completion: { finished in 
      fromViewController?.view.removeFromSuperview() 
      transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 
     }) 

    } 

} 

class CustomInteractiveController: NSObject, UIViewControllerInteractiveTransitioning { 

    func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) { 

     // I think the edge screen pan gesture goes here? Again, any advice is greatly appreciated! 

    } 

} 
+1

對於那個低估了這個問題的人,我很感激原因。我花了很多時間研究和編寫這段代碼,並且提出了一個非常具體的問題,它給了什麼? – sconewolf

回答

1

一般情況下,寫一個互動的自定義過渡動畫的程序是:轉變開始

  1. 之前,必須給予負責的過渡委託的視圖控制器。

  2. 您將擁有一個跟蹤交互式手勢的手勢識別器。當手勢識別器識別時,它觸發到新視圖控制器的轉換。

  3. 隨着轉換開始,代表將被要求提供動畫控制器。您將返回一個UIViewControllerAnimatedTransitioning對象。

  4. 該代表還將被要求提供交互控制器。您將返回一個UIViewControllerInteractiveTransitioning對象(或nil以防止轉換爲交互式)。該對象實現了startInteractiveTransition(_:)

  5. 手勢識別器繼續在轉換上下文中不斷調用updateInteractiveTransition(_:),並管理動畫幀。

  6. 手勢遲早會結束。此時,我們必須決定是否宣佈過渡完成或取消。一種典型的方法是說,如果用戶執行了超過一半的完整手勢,則構成完成;否則,它構成取消。我們相應地完成動畫。

  7. 動畫現在已完成,其完成功能被調用。我們必須調用轉換上下文的finishInteractiveTransitioncancelInteractiveTransition,然後用一個參數來調用其completeTransition(_:),該參數指出轉換是完成還是取消。

  8. 我們的animationEnded被調用,我們清理。

在過去,你可以使用一個UIPercentDrivenInteractiveTransition對象來幫助你,但我總是用我的自定義過渡動畫時下UIViewPropertyAnimator(iOS版10及更高版本);你將不得不開始重寫你的整個代碼來做到這一點。我通常保留三個實例屬性:UIViewPropertyAnimator,轉換上下文(因爲手勢識別器需要引用)以及一個Bool標誌,表明這是否是交互式動畫(因爲相同的代碼可以重複用於交互式和非交互式版本動畫)。

+0

我接受了您的建議,並使用'UIViewPropertyAnimator'重構了動畫。我創建了一個Gist https://gist.github.com/sconewolf/7a849fc691b63cf8721d6151831feae8編輯,但無法弄清楚如何將平移手勢識別器和處理程序鏈接到交互控制器(在底部)。缺少的鏈接是什麼?有很多教程使用'UIPercentDrivenInteractiveTransition'(我過去做過但因0.999黑客而感到厭惡),但沒有找到使用「UIViewPropertyAnimator」的教程(很明顯,因爲它到現在爲止還沒有iOS 10 )。 – sconewolf

+0

如果你知道我是誰,你知道我的書的代碼是什麼,你可以找到示例代碼來演示我在答案中所說的內容。 – matt

相關問題