Hola, soy Luis y aquí les traigo un nuevo artículo.
Además de lo que parece ser más simple y «pirateado» de lo que crees, la verdad es que siempre vemos al principio, las transiciones de iOS como algo muy difícil, y no es «extraño» ver que esta es una de las razones que siempre buscamos una biblioteca para entregarnos esto, pero ¿realmente lo necesitamos?.
Tenemos piezas para hacer la transición, pero la más importante es una delegate
, necesitamos implementar el UIViewControllerTransitioningDelegate
protocolo, de forma muy sencilla este será el protocolo / clase
que se encargará de nuestra transición.
De una manera muy simple este es el flujo de navegación normal:
Índice
Transición normal sin transición personalizada
- Tenemos nuestro primer controlador de vista y queremos pasar al segundo con una transición personalizada.
- Queremos volver del segundo al primero mediante una transición personalizada.
Necesitamos «nombrar» un objeto / clase
entre estos 2
controladores de vista para realizar nuestra transición de animación personalizada, piense que llamamos a una capa entre estos dos que será responsable de esta transición, esto se convertirá en esto:
Tener un delegado que maneje nuestra transición personalizada
Esto no es algo nuevo, en realidad cada vez que realizas una transición, simplemente llamándote a la siguiente vista estás usando esto, es solo la predeterminada, lo que estamos haciendo es usar una personalizada que «anula» la predeterminada.
Cree un proyecto de demostración, cualquier formato que desee, en nuestro escenario estamos usando el guión gráfico «Principal» cuando creamos un nuevo proyecto, cambie el nombre del controlador de vista predeterminado que Xcode crea de "ViewController"
a "FirstViewController"
, y cree otra vista controlador y el nombre como "SecondViewController"
sólo para ser más visual.
Vaya a su guión gráfico y cree el controlador de vista respectivo para SecondViewController
también.
Dentro de cada controlador de vista, para el primero, agregue un botón con la cadena «Ir a la siguiente» y en la segunda vista del controlador de vista cree un botón con la cadena «Regresar».
Deberías tener algo como esto:
Agregue el respectivo @IBAction
en cada controlador de vista:
Controlador de primera vista:
@IBAction func goNext(_ sender: Any)
Y para el segundo controlador de vista:
@IBAction func getBack(_ sender: Any)
Pasemos a la parte sobre la transición en sí, creemos nuestro delegado de transición personalizado, para esto cree una clase llamada TransitionDelegate
e implementar dos métodos:
Primero, el método que se encargará de presentar el controlador de vista:
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
Ahora implementemos el método que será responsable cuando descartemos, volvamos al controlador de vista anterior:
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
Necesitamos establecer cómo será nuestra transición, el efecto en sí que queremos hacer, ya que este es el propósito, tener una transición personalizada, es posible que vea una advertencia del Xcode, arreglaremos este último.
Después de implementar el delegado, simplemente configuramos dos métodos, y esperan un objeto de tipo UIViewControllerAnimatedTransitioning
, ahora es la otra parte importante, primero estamos configurando la clase que será responsable de la transición.
La razón por la que estamos haciendo esto es sobre el efecto en sí, y necesitamos crear / tener
un objeto de este tipo, él será el que hará que nuestra transición tenga efecto.
Creemos un efecto simple para que comprenda, creemos una clase que herede NSObject
y agregue este contenido:
import UIKitclass FadePushAnimator: NSObject, UIViewControllerAnimatedTransitioning func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval return 0.5 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) guard let toViewController = transitionContext.viewController(forKey: .to) else return transitionContext.containerView.addSubview(toViewController.view) toViewController.view.alpha = 0 let duration = self.transitionDuration(using: transitionContext) UIView.animate(withDuration: duration, animations: toViewController.view.alpha = 1 , completion: _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) )
1 – Duración de la transición
Aquí es donde nuestro delegado preguntará cuánto debe durar nuestra transición, es obligatorio.
2 – Transición animada
Aquí es donde ocurre la “magia”, es el efecto en sí, veamos la implementación y comprendamos.
2.1 – Esta animación solo queremos que se haga cuando voy "a"
, por eso primero validamos esto, obtenemos el "contexto de transición"
, imaginamos como un "cuadro"
que cuando iniciamos nuestra navegación tiene la referencia para qué pantalla estamos llamando y de dónde venimos.
2.2 – Agregamos la "vista"
del controlador de vista a la vista del contenedor de contexto de transición, lo que estamos haciendo es agregar al "contexto"
la vista que queremos que sea animada, ya que la animación es básicamente tenemos la "instantánea"
que ponemos en un “lugar temporal”
y aplicamos los efectos que queramos, sin interferir en la vista original.
2.3 – La parte de animación, este es solo el formato normal en el que hacemos la animación, en realidad puedes usar cualquier otro formato de animación aquí, CALayer
por ejemplo, cualquier cosa para hacer tu animación.
Tenemos la animación para cuando nos vayamos, es bueno tener una para volver, ya que ya estamos viendo las diferencias, así que creemos una para cuando regresemos.
import UIKitclass FadePopAnimator: NSObject, UIViewControllerAnimatedTransitioning func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval return 0.5 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) guard let fromViewController = transitionContext.viewController(forKey: .from), let toViewController = transitionContext.viewController(forKey: .to) else return transitionContext.containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view) let duration = self.transitionDuration(using: transitionContext) UIView.animate(withDuration: duration, animations: fromViewController.view.alpha = 0 , completion: _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) )
No profundizaremos demasiado, ya que ahora puedes entender algunas diferencias, como, ahora verificamos si tenemos la vista que voy a volver a usar. transitionContext.viewController(forKey: .from)
En este contexto lo que estamos haciendo es “desvanecer” y por esta razón, agregamos ambas vistas a nuestro contenedor de contexto, pero agregamos la vista que obtendremos abajo la vista real, esto se debe a que está «conectado» a la forma en que quiero hacer mi animación.
Una cosa que no he mencionado antes cuando finaliza la animación es obligatorio llamar al método completeTransition(
hacemos esto, por ejemplo, dentro del bloque de finalización de la función de animación UIView.
Para mí, me gusta organizar mis clases en un lugar separado, es una opción, pero así es como se ve mi estructura:
Estructura del proyecto
Ahora que tenemos todas las piezas para aplicar nuestra animación comencemos a completar todos los puntos faltantes para tener la animación, la más simple es volver a nuestra clase.
TransitionDelegate
y configure la animación que usaremos para cada paso de transición, primero configure la animación presente / push
.
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? return FadePushAnimator()
Solo tenemos que crear la instancia FadePushAnimator()
y regrese con este método.
Hagamos lo mismo cuando descartemos / pop
.
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? return FadePopAnimator()
Es lo mismo, ahora solo devolvemos la instancia FadePopAnimator()
para cuando despidamos.
Solo necesitamos configurar nuestro delegado de transición del controlador de vista para usar nuestra clase de delegado de transición personalizada.
En la primera vista, el controlador primero crea la instancia de nuestro delegado, así:
let transitionDelegate: UIViewControllerTransitioningDelegate = TransitionDelegate()
En la vista, la carga configuró este delegado de transición de vista a nuestro delegado personalizado de esta manera:
override func viewDidLoad() super.viewDidLoad() self.transitioningDelegate = transitionDelegate
En este paso básicamente tienes todo listo, ahora solo necesitamos llamar a nuestro segundo controlador de vista, ya que no estamos usando el controlador de navegación, necesitamos llamar al método presentViewController:animated:completion:
, dentro del método @IBAction func goNext(_ sender: Any)
hagamos así:
let secondView = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: String(describing: SecondViewController.self)) secondView.transitioningDelegate = transitionDelegate self.present(secondView, animated: true, completion: nil)
Esto no debería ser nuevo para usted, obtenemos la instancia del guión gráfico, después de tener la instancia, configuramos el segundo delegado de transición del controlador de vista para usar lo mismo que estamos usando, no necesito recrear, además puedo hacerlo y nada cambiará.
Y finalmente, simplemente llame al método presente, configurando que queremos que el sistema sea animado, es lo suficientemente inteligente como para verificar al delegado, ya que nosotros usará nuestro delegado personalizado.
En el segundo controlador de vista, diría que es incluso menos código, vaya al segundo controlador de vista y dentro del @IBAction func getBack(_ sender: Any)
solo agrega esto:
self.dismiss(animated: true, completion: nil)
Ahora que se ejecuta, verá que la transición de caras que acabamos de configurar funcionará bien, y no hay mucho más que esto.
Hagamos un resumen simple de los pasos que necesitamos en un formato muy simple:
- La clase responsable de la transición, para nosotros, es
TransitionDelegate
, este será el delegado que configuraremos para todos los controladores de vista que queremos que tengan una transición personalizada. - El objeto que tiene nuestra transición personalizada, tenemos uno para empujar y otro para hacer estallar.
Solo esto, no es tan complicado, ¿verdad? De una manera muy simple configuramos esta transición, para el controlador de navegación el principio es exactamente el mismo, el delegado implementa otro método por supuesto, pero usa los mismos “componentes”, crearé otro tutorial para esta situación también.
Espero que les haya gustado, y si tienen algún comentario por favor compartan conmigo, quieren pedir algo, avíseme, si desde aquí hicieron algún código avíseme también, compartan su código, no hay código malo o “junior ”, Comparta lo que hizo, ¡puede ayudar a otros a compartir su código!
Por favor, comparta la mayor cantidad posible, ya que esto me ayuda a llegar a más personas y seguir escribiendo, ¿encontró algún error? ¡Ponte en contacto, ayudemos juntos!
Enlace al proyecto final que puede encontrar aquí: https://github.com/felipeflorencio/CustomViewControllerTransitionSample.
Documentación de referencia de Apple: https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html.
Espero que te haya gustado, y si tienes algún comentario, compártelo conmigo.
Añadir comentario