2017-09-04 1 views
0

Ich unterordnete UINavigationController und erstellte ein nicht interaktives Animationsobjekt, das die Push- und Pop-Übergänge behandelt. Wie füge ich einen UIScreenEdgePanGestureRecognizer hinzu, um die unten stehende benutzerdefinierte Pop-Animation zu bearbeiten? Ich bin irgendwie verwirrt darüber, wohin ich von hier gehen sollte, also wäre jede Hilfe großartig, danke!Wie füge ich einen Pan-Gesten-Erkenner für den Bildschirmrand hinzu, um mit dieser Pop-Animation umzugehen?

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

Für die Person, die diese Frage abgelehnt hat, würde ich einen Grund zu schätzen wissen. Ich habe viel Zeit damit verbracht, diesen Code zu recherchieren und zu schreiben, und ich habe eine sehr spezifische Frage gestellt, was gibt es? – sconewolf

Antwort

1

Im Allgemeinen ist das Verfahren für eine interaktive individuelle Übergangsanimation zu schreiben ist:

  1. Bevor der Übergang beginnt, müssen Sie den View-Controller verantwortlich für den Übergang eines Delegierten gegeben haben.

  2. Sie haben eine Gestenerkennung, die die interaktive Geste verfolgt. Wenn der Gestenerkenner erkennt, löst er den Übergang zum neuen Ansichtscontroller aus.

  3. Wenn der Übergang beginnt, wird der Delegat nach einem Animationscontroller gefragt. Sie werden ein UIViewControllerAnimatedTransitioning-Objekt zurückgeben.

  4. Der Delegierte wird auch nach einem Interaktionscontroller gefragt. Sie geben ein UIViewControllerInteractiveTransitioning-Objekt zurück (oder nil, um zu verhindern, dass der Übergang interaktiv wird). Dieses Objekt implementiert startInteractiveTransition(_:).

  5. Der Gestenerkenner setzt fort, updateInteractiveTransition(_:) auf dem Übergangskontext ständig zu rufen, sowie die Rahmen der Animation zu verwalten.

  6. Früher oder später wird die Geste enden. An dieser Stelle müssen wir entscheiden, ob der Übergang abgeschlossen oder abgebrochen werden soll. Ein typischer Ansatz besteht darin zu sagen, dass, wenn der Benutzer mehr als die Hälfte der vollständigen Geste ausführt, dies eine Vervollständigung darstellt; Andernfalls stellt es eine Stornierung dar. Wir beenden die Animation entsprechend.

  7. Die Animation ist nun abgeschlossen und ihre Abschlussfunktion wird aufgerufen. Wir müssen den Übergangskontext finishInteractiveTransition oder cancelInteractiveTransition aufrufen und dann completeTransition(_:) mit einem Argument aufrufen, das angibt, ob der Übergang beendet oder abgebrochen wurde.

  8. Unsere animationEnded heißt, und wir aufräumen.

In der Vergangenheit können Sie ein UIPercentDrivenInteractiveTransition-Objekt verwenden, um Ihnen zu helfen, aber ich habe immer einen UIViewPropertyAnimator für meine benutzerdefinierten Übergang Animationen heute (iOS 10 und höher) verwenden; Sie müssten damit beginnen, Ihren gesamten Code neu zu schreiben. Normalerweise behalte ich drei Instanzeigenschaften: den UIViewPropertyAnimator, den Übergangskontext (weil der Gestenerkenner eine Referenz benötigt) und ein Bool-Flag, das angibt, ob es sich um eine interaktive Animation handelt (weil derselbe Code für interaktive und nicht interaktive Versionen desselben wiederverwendet werden kann) Animation).

+0

Ich nahm Ihren Rat und refaktorierte die Animation mit 'UIViewPropertyAnimator'. Ich habe eine Gist https://gist.github.com/sconewolf/7a849fc691b63cf8721d6151831feae8 mit den Änderungen erstellt, kann aber nicht herausfinden, wie man den Pan-Gesten-Erkenner & Handler mit dem interaktiven Controller verbindet (ganz unten). Was ist das fehlende Glied?Es gibt eine Menge Tutorials, die 'UIPercentDrivenInteractiveTransition' verwenden (was ich in der Vergangenheit gemacht habe, aber wegen des Hacks von 0.999 verabscheue), aber keine Tutorials mit' UIViewPropertyAnimator' gefunden haben (offensichtlich, weil es bis jetzt nicht mit iOS 10 existierte)). – sconewolf

+0

Wenn Sie wissen, wer ich bin, wissen Sie, wo mein Buchcode ist, und Sie können den Buchbeispielcode finden, der zeigt, was ich in meiner Antwort gesagt habe. – matt

Verwandte Themen