iphone objective-c animation presentmodalviewcontroller

iphone - Animate presentModalViewController de derecha/izquierda



presentviewcontroller animated completion (5)

Cuando está presente:

CATransition *transition = [CATransition animation]; transition.duration = 0.3; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromRight; [self.view.window.layer addAnimation:transition forKey:nil]; [self presentModalViewController:viewCtrl animated:NO];

Cuando descarte:

CATransition *transition = [CATransition animation]; transition.duration = 0.3; transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromLeft; [self.view.window.layer addAnimation:transition forKey:nil]; [self dismissModalViewControllerAnimated:NO];

Actualmente estoy usando [self presentModalViewController :newVC animated:YES] . Deseo presentar newViewcontroller desde la izquierda / derecha / arriba / abajo con un efecto push. Traté de usar CATransition pero muestra una pantalla en negro entre la transición.


Después de X> = 4 horas de trabajo, esto funciona sin "rasgar" u otros artefactos de fondo:

class AboutTransition: NSObject, UIViewControllerAnimatedTransitioning { let presenting: Bool let duration: NSTimeInterval init(presenting: Bool, duration: NSTimeInterval = 0.25) { self.presenting = presenting self.duration = duration } @objc func transitionDuration(ctx: UIViewControllerContextTransitioning) -> NSTimeInterval { return duration } @objc func animateTransition(ctx: UIViewControllerContextTransitioning) { let duration = transitionDuration(ctx) let containerView = ctx.containerView() let fromViewController = ctx.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toViewController = ctx.viewControllerForKey(UITransitionContextToViewControllerKey)! let fromView = fromViewController.view // 7.0 & 8.0 compatible vs. viewForKey: let toView = toViewController.view // 7.0 & 8.0 compatible vs. viewForKey: containerView.addSubview(fromView) containerView.addSubview(toView) let offScreenRight = CGAffineTransformMakeTranslation(containerView.frame.width, 0) let offScreenLeft = CGAffineTransformMakeTranslation(-containerView.frame.width, 0) fromView.transform = CGAffineTransformIdentity toView.transform = self.presenting ? offScreenRight : offScreenLeft UIView.animateWithDuration(duration, delay:0, options:UIViewAnimationOptions(0), animations: { fromView.transform = self.presenting ? offScreenLeft : offScreenRight toView.transform = CGAffineTransformIdentity }, completion: { (finished: Bool) in ctx.completeTransition(finished) if finished { fromView.removeFromSuperview() fromView.frame = toView.frame // reset the frame for reuse, otherwise frame transforms will accumulate } }) } }

Luego, en AppDelegate.swift :

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDelegate { lazy var window: UIWindow? = { return UIWindow(frame: UIScreen.mainScreen().bounds) }() lazy var storyboard = UIStoryboard(name: "Main", bundle: nil) lazy var nav: UINavigationController = { var r = self.storyboard.instantiateInitialViewController() as! UINavigationController r.delegate = self return r }() func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { self.window!.rootViewController = nav self.window!.makeKeyAndVisible() // .. other setup return true } // ... // MARK: - UINavigationControllerDelegate func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // Example of a SettingsViewController which pushes AboutViewController if fromVC is SettingsViewController && toVC is AboutViewController { // Push to About return AboutTransition(presenting: true) } else if fromVC is AboutViewController && toVC is SettingsViewController { // Pop to Settings return AboutTransition(presenting: false) } return nil } }

Esto supone que una aplicación está utilizando el guión gráfico predeterminado con un VC inicial como un UINavigationController

Actualización para swift 3/4

class LTRTransition: NSObject, UIViewControllerAnimatedTransitioning { let presenting: Bool let duration: TimeInterval init(presenting: Bool, duration: TimeInterval = Theme.currentTheme.animationDuration) { self.presenting = presenting self.duration = duration } @objc func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval { return duration } @objc func animateTransition(using ctx: UIViewControllerContextTransitioning) { let duration = transitionDuration(using: ctx) let containerView = ctx.containerView let fromViewController = ctx.viewController(forKey: UITransitionContextViewControllerKey.from)! let toViewController = ctx.viewController(forKey: UITransitionContextViewControllerKey.to)! guard let fromView = fromViewController.view, // 7.0 & 8.0 compatible vs. viewForKey: let toView = toViewController.view // 7.0 & 8.0 compatible vs. viewForKey: else { assertionFailure("fix this") return } containerView.addSubview(fromView) containerView.addSubview(toView) let offScreenRight = CGAffineTransform(translationX: containerView.frame.width, y: 0) let offScreenLeft = CGAffineTransform(translationX: -containerView.frame.width, y: 0) fromView.transform = CGAffineTransform.identity toView.transform = self.presenting ? offScreenRight : offScreenLeft UIView.animate(withDuration: duration, delay:0, options:UIViewAnimationOptions(rawValue: 0), animations: { fromView.transform = self.presenting ? offScreenLeft : offScreenRight toView.transform = CGAffineTransform.identity }, completion: { (finished: Bool) in ctx.completeTransition(finished) if finished { fromView.removeFromSuperview() // this screws up dismissal. at least on ios10 it does fromView.frame = toView.frame // reset the frame for reuse, otherwise frame transforms will accumulate } }) } }

Y la implementación transitioniningDelegate para el VC se empuja / descarta:

extension WhateverVCyouArePresentingFrom: UIViewControllerTransitioningDelegate { public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return LTRTransition(presenting: true) } public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return LTRTransition(presenting: false) } }


Puede establecer un transitioningDelegate de transitioningDelegate en el controlador de vista que desea presentar. Debe cumplir con los protocolos UIViewControllerTransitioningDelegate y UIViewControllerAnimatedTransitioning . Y al implementar animateTransition(transitionContext: UIViewControllerContextTransitioning) puede animar cualquiera de las subvistas de los controladores de vista.

Función que realiza la transición

class fromViewController : UIViewController { let transitionManager = TransitionManager() func transitionToViewController() { toController.transitioningDelegate = transitionManager presentViewController(toController, animated: true, completion: nil) } }

Entonces, el TransitionManager se ve así:

import UIKit class TransitionManager : UIPercentDrivenInteractiveTransition { var presenting = false } // MARK: UIViewControllerAnimatedTransitioning extension TransitionManager : UIViewControllerAnimatedTransitioning { func animateTransition(transitionContext: UIViewControllerContextTransitioning) { let container = transitionContext.containerView() let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! let offScreenRight = CGAffineTransformMakeTranslation(container.frame.width, 0) let offScreenLeft = CGAffineTransformMakeTranslation(-container.frame.width, 0) toView.transform = self.presenting ? offScreenRight : offScreenLeft container.addSubview(toView) container.addSubview(fromView) let duration = self.transitionDuration(transitionContext) UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0.8, options: nil, animations: { fromView.transform = self.presenting ? offScreenLeft : offScreenRight toView.transform = CGAffineTransformIdentity }, completion: { finished in transitionContext.completeTransition(true) }) } func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { return 0.3 } } // MARK: UIViewControllerTransitioningDelegate extension TransitionManager : UIViewControllerTransitioningDelegate { func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { self.presenting = true return self } func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { self.presenting = false return self } }


Solo hay cuatro UIModalTransitionStyles:

UIModalTransitionStyleCoverVertical UIModalTransitionStyleFlipHorizontal UIModalTransitionStyleCrossDissolve UIModalTransitionStylePartialCurl

Por ejemplo:

UIViewController *controller = [[[MyViewController alloc] init] autorelease]; UIModalTransitionStyle trans = UIModalTransitionStyleFlipHorizontal; [UIView beginAnimations: nil context: nil]; [UIView setAnimationTransition: trans forView: [self window] cache: YES]; [navController presentModalViewController: controller animated: NO]; [UIView commitAnimations];


Yo tuve el mismo problema. Supongamos que desea presentar un controlador de vista 2 desde el controlador de vista 1. En el primer uso de controlador de vista

[self presentModalViewController: controller animated: NO]];

En el controlador de la segunda vista, en el método viewWillAppear: agregue el código

CATransition *animation = [CATransition animation]; [animation setDelegate:self]; [animation setType:kCATransitionPush]; [animation setSubtype:kCATransitionFromRight]; [animation setDuration:0.40]; [animation setTimingFunction: [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut]]; [self.view.layer addAnimation:animation forKey:kCATransition];

Funcionará bien. Si aparece una pantalla negra nuevamente, si está usando el controlador de navegación, reemplace

[self.view.layer addAnimation:animation forKey:kCATransition];

con

[self.navigationController.view.layer addAnimation:animation forKey:kCATransition];