Ich habe einige Tutorials befolgt, um beim Übergang von einer Ansicht zur anderen eine benutzerdefinierte Animation zu erstellen.
Mein Testprojekt mit benutzerdefiniertem Segue von hier aus funktioniert einwandfrei, aber jemand hat mir gesagt, dass es nicht mehr empfohlen wird, benutzerdefinierte Animationen innerhalb eines benutzerdefinierten Segues zu erstellen, und ich sollte verwenden UIViewControllerAnimatedTransitioning
.
Ich habe mehrere Tutorials befolgt, die dieses Protokoll verwenden, aber alle handeln von der modalen Präsentation (zum Beispiel dieses Tutorial ).
Was ich versuche, ist ein Push-Segue innerhalb eines Navigationscontrollerbaums, aber wenn ich versuche, dasselbe mit einem Show- (Push-) Segue zu tun, funktioniert es nicht mehr.
Bitte sagen Sie mir, wie Sie in einem Navigationscontroller eine benutzerdefinierte Übergangsanimation von einer Ansicht zur anderen ausführen können.
Und gibt es überhaupt eine Methode für alle Übergangsanimationen? Es wäre umständlich, wenn ich eines Tages die gleiche Animation machen möchte, aber am Ende den Code zweimal duplizieren muss, um am Übergang von Modal zu Controller zu arbeiten.
self.navigationController.delegate = self;
inviewDidLoad
. Möglicherweise erhalten Sie eine Warnung, es sei denn, Sie geben in der@interface
Zeile an, dass Ihr View Controller dem<UINavigationControllerDelegate>
Protokoll entspricht .Antworten:
Um einen benutzerdefinierten Übergang mit Navigation Controller (
UINavigationController
) durchzuführen, sollten Sie:Definieren Sie Ihren View Controller so, dass er dem
UINavigationControllerDelegate
Protokoll entspricht. Sie können beispielsweise eine private Klassenerweiterung in der.m
Datei Ihres View Controllers haben , die die Konformität mit diesem Protokoll angibt:@interface ViewController () <UINavigationControllerDelegate> @end
Stellen Sie sicher, dass Sie Ihren View Controller tatsächlich als Delegierten Ihres Navigationscontrollers angeben:
- (void)viewDidLoad { [super viewDidLoad]; self.navigationController.delegate = self; }
Implementieren Sie
animationControllerForOperation
in Ihrem View Controller:- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC { if (operation == UINavigationControllerOperationPush) return [[PushAnimator alloc] init]; if (operation == UINavigationControllerOperationPop) return [[PopAnimator alloc] init]; return nil; }
Implementieren Sie Animatoren für Push- und Pop-Animationen, z.
@interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @implementation PushAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; [[transitionContext containerView] addSubview:toViewController.view]; toViewController.view.alpha = 0.0; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ toViewController.view.alpha = 1.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end @implementation PopAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view]; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromViewController.view.alpha = 0.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end
Das verblasst zwar beim Übergang, aber Sie können die Animation jederzeit nach Belieben anpassen.
Wenn Sie interaktive Gesten verarbeiten möchten (z. B. das native Wischen von links nach rechts zum Pop), müssen Sie einen Interaktionscontroller implementieren:
Definieren Sie eine Eigenschaft für einen Interaktionscontroller (ein Objekt, das den Anforderungen entspricht
UIViewControllerInteractiveTransitioning
):@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;
Dies
UIPercentDrivenInteractiveTransition
ist ein schönes Objekt, das das Aktualisieren Ihrer benutzerdefinierten Animation auf der Grundlage der Vollständigkeit der Geste erleichtert.Fügen Sie Ihrer Ansicht eine Gestenerkennung hinzu. Hier implementiere ich nur den linken Gestenerkenner, um einen Pop zu simulieren:
UIScreenEdgePanGestureRecognizer *edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFromLeftEdge:)]; edge.edges = UIRectEdgeLeft; [view addGestureRecognizer:edge];
Implementieren Sie den Gestenerkennungs-Handler:
/** Handle swipe from left edge * * This is the "action" selector that is called when a left screen edge gesture recognizer starts. * * This will instantiate a UIPercentDrivenInteractiveTransition when the gesture starts, * update it as the gesture is "changed", and will finish and release it when the gesture * ends. * * @param gesture The screen edge pan gesture recognizer. */ - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture { CGPoint translate = [gesture translationInView:gesture.view]; CGFloat percent = translate.x / gesture.view.bounds.size.width; if (gesture.state == UIGestureRecognizerStateBegan) { self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; [self popViewControllerAnimated:TRUE]; } else if (gesture.state == UIGestureRecognizerStateChanged) { [self.interactionController updateInteractiveTransition:percent]; } else if (gesture.state == UIGestureRecognizerStateEnded) { CGPoint velocity = [gesture velocityInView:gesture.view]; if (percent > 0.5 || velocity.x > 0) { [self.interactionController finishInteractiveTransition]; } else { [self.interactionController cancelInteractiveTransition]; } self.interactionController = nil; } }
In Ihrem Navigationscontroller-Delegaten müssen Sie auch die
interactionControllerForAnimationController
Delegierungsmethode implementieren- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController { return self.interactionController; }
Wenn Sie "UINavigationController Custom Transition Tutorial" googeln, erhalten Sie viele Treffer. Oder sehen Sie sich das Video zu benutzerdefinierten Übergängen von WWDC 2013 an .
quelle
UIPercentDrivenInteractiveTransition
(was den Prozess erheblich vereinfacht). Ich habe oben einige relevante Code-Schnipsel hinzugefügt.animationControllerForOperation
können einfach dasfromVC
und / oder überprüfentoVC
und zurückkehren,nil
wenn Sie nicht möchten, dass eine benutzerdefinierte Animation ausgeführt wird. Am einfachsten ist es, zu überprüfen, ob es sich um eine bestimmte Klasse handelt. Eleganter können Sie ein optionales Protokoll entwerfen, an das sich View-Controller anpassen können, mit einer booleschen Eigenschaft, die angibt, ob sie das benutzerdefinierte Push / Pop möchten oder nicht.Möglicherweise möchten Sie den folgenden Code bereits hinzufügen
addSubview
toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
Aus einer anderen Frage: Benutzerdefinierter Übergang für Push-Animation mit Navigationscontroller auf iOS-9
Aus der Apple-Dokumentation für finalFrameForViewController:
quelle
Unter Verwendung der perfekten Antworten von Rob & Q i ist hier der vereinfachte Swift-Code, der dieselbe Fade-Animation für .push und .pop verwendet:
extension YourViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { //INFO: use UINavigationControllerOperation.push or UINavigationControllerOperation.pop to detect the 'direction' of the navigation class FadeAnimation: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) if let vc = toViewController { transitionContext.finalFrame(for: vc) transitionContext.containerView.addSubview(vc.view) vc.view.alpha = 0.0 UIView.animate(withDuration: self.transitionDuration(using: transitionContext), animations: { vc.view.alpha = 1.0 }, completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } else { NSLog("Oops! Something went wrong! 'ToView' controller is nill") } } } return FadeAnimation() } }
Vergessen Sie nicht, den Delegaten in der viewDidLoad () -Methode von YourViewController festzulegen:
override func viewDidLoad() { //... self.navigationController?.delegate = self //... }
quelle
Es funktioniert sowohl schnell 3 als auch 4
@IBAction func NextView(_ sender: UIButton) { let newVC = self.storyboard?.instantiateViewControllerWithIdentifier(withIdentifier: "NewVC") as! NewViewController let transition = CATransition() transition.duration = 0.5 transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) transition.type = kCATransitionPush transition.subtype = kCAGravityLeft //instead "kCAGravityLeft" try with different transition subtypes self.navigationController?.view.layer.add(transition, forKey: kCATransition) self.navigationController?.pushViewController(newVC, animated: false) }
quelle