Aplicar transición de zoom al navegar entre vistas

SwiftUI, por defecto, proporciona una transición automática al navegar de una vista a otra sin necesidad de código adicional. Sin embargo, a partir de iOS 18, puedes utilizar una transición de tipo zoom o acercamiento para crear una experiencia de usuario más agradable. Esto es posible gracias a los nuevos modificadores navigationTransition y matchedTransitionSource.

Código de ejemplo

Para demostrar el uso de estos modificadores, partiremos del siguiente código de ejemplo:

import SwiftUI
// 1
struct ContentView: View {
var body: some View {
// 2
NavigationStack {
// 3
NavigationLink("👉 Tap Me 👈") {
// 4
Text("Hello world")
}
}
}
}
  1. Se define ContentView como vista principal.
  2. Se define un tipo de navegación en stack (pila).
  3. Se establece un NavigationLink que, al ser presionado, navega desde ContentView a la vista de destino.
  4. Se muestra un Text como la vista de destino.
Transición por defecto de una vista a otra usando NavigationStack

En la imagen, se observa la transición de una vista a otra contenida en un NavigationStack. El objetivo es usar una transición de tipo zoom al navegar de la vista principal a la vista de destino.

Usando el modificador navigationTransition

navigationTransition es un modificador que se aplica a una vista para indicar el estilo de transición al navegar a dicha vista. En el caso del código de ejemplo, navigationTransition se aplicará a la vista de destino. Su definición es:

nonisolated
func navigationTransition(_ style: some NavigationTransition) -> some View

El modificador tiene el parámetro style, donde se especifica el estilo de transición deseado. Estos son:

  1. automatic: Es la transición por defecto y varía según cómo se presenta la vista, por ejemplo, NavigationStack, sheet, fullScreenCover, entre otros.
  2. zoom(sourceID: some Hashable, in namespace: Namespace.ID): Aplica una transición de tipo zoom. Tiene los parámetros sourceID para establecer un identificador desde donde se originó la transición (veremos su utilidad más adelante) y namespace para indicar dónde está definido el sourceID.

Quizás en el futuro Apple permita establecer transiciones personalizadas además de estos dos 🤞.

Para aplicar la transición zoom al código de ejemplo, primero crea una variable namespace en ContentView que utilice el property wrapper @Namespace:

@Namespace var namespace

@Namespace se utiliza para coordinar animaciones entre vistas.

Añade el modificador navigationTransition con el estilo de transición zoom al Text("Hello world"):

.navigationTransition(
.zoom(sourceID: 1, in: namespace)
)
Transición de zoom de una vista a otra usando NavigationStack

¡Lo has logrado! Con estas simples líneas de código, ya tienes una transición de tipo zoom para navegar a la vista de destino y volver a la vista principal. Además, zoom permite volver a la pantalla anterior con un gesto de presionado más deslizamiento hacia abajo.

Puedes aplicar la transición zoom a otros tipos de navegación como sheet y fullScreenCover.

Usando el modificador matchedTransitionSource

matchedTransitionSource mejora aún más el comportamiento de zoom, ya que identifica la vista específica que origina la transición, permitiendo que forme parte de la transición y le indique al usuario de forma más clara qué vista provocó la navegación. En el código de ejemplo, sería el NavigationLink. Su definición es:

nonisolated
func matchedTransitionSource(
id: some Hashable,
in namespace: Namespace.ID
) -> some View

Este modificador tiene dos parámetros:

  1. id: El identificador origen de la transición.
  2. namespace: Indica dónde está definido el id.

Agrega el modificador al NavigationLink del código de ejemplo:

.matchedTransitionSource(id: 1, in: namespace)
Transición de zoom con matchedTransitionSource de una vista a otra usando NavigationStack

Como se observa en la imagen, el NavigationLink "👉 Tap Me 👈" forma parte del zoom. Esto es posible porque sourceID del modificador navigationTransition y id de matchedTransitionSource son el mismo y pertenecen al mismo namespace, creando una animación más fluida.

El código de ejemplo completo aplicando la transición zoom quedaría así:

import SwiftUI
struct ContentView: View {
@Namespace var namespace
var body: some View {
NavigationStack {
NavigationLink("👉 Tap Me 👈") {
Text("Hello world")
.navigationTransition(
.zoom(sourceID: 1, in: namespace)
)
}
.matchedTransitionSource(id: 1, in: namespace)
}
}
}

Para casos donde tengas un arreglo de múltiples elementos, puedes asignar el identificador único del elemento en sourceID y id a ambos modificadores, y así tener una transición única para cada elemento. Ejemplo:

import SwiftUI
// 1
struct Pet: Identifiable, Hashable {
let id = UUID()
let name: String
let emoji: String
}
struct PetsView: View {
@Namespace var namespace
let pets = [
Pet(name: "Dog", emoji: "🐶"),
Pet(name: "Cat", emoji: "🐱"),
Pet(name: "Bird", emoji: "🦜")
]
var body: some View {
NavigationStack {
List(pets) { pet in
NavigationLink(pet.name, value: pet)
// 2
.matchedTransitionSource(id: pet.id, in: namespace)
}
.navigationDestination(for: Pet.self) { pet in
Text(pet.emoji)
.navigationTransition(
// 3
.zoom(sourceID: pet.id, in: namespace)
)
}
}
}
}
  1. Se define la estructura Pet para mostrar un listado de mascotas. Posee la propiedad id como identificador único a utilizar en los modificadores navigationTransition y matchedTransitionSource.
  2. Por cada pet del listado se asigna su id en matchedTransitionSource.
  3. Se establece el id de la mascota como sourceId de zoom.
Transición de zoom con matchedTransitionSource de una vista con un listado a otra usando NavigationStack

El modificador matchedTransitionSource tiene otro parámetro llamado configuration para aplicar los modificadores background, clipShape y shadow a la vista específica que origina la transición:

nonisolated
func matchedTransitionSource(
id: some Hashable,
in namespace: Namespace.ID,
configuration: (EmptyMatchedTransitionSourceConfiguration) -> some MatchedTransitionSourceConfiguration
) -> some View

Compatibilidad

La transición zoom y los modificadores navigationTransition y matchedTransitionSource pueden ser utilizados a partir de las siguientes versiones de los sistemas operativos de Apple:

  • iOS 18.0+.
  • iPadOS 18.0+.
  • Mac Catalyst 13.0+.
  • macOS 15.0+.
  • tvOS 18.0+.
  • visionOS 2.0+.
  • watchOS 11.0+.

Conclusión

SwiftUI a partir de iOS 18 ofrece nuevas capacidades para mejorar la experiencia del usuario mediante transiciones de tipo zoom al navegar entre vistas. Los modificadores navigationTransition y matchedTransitionSource permiten aplicar y coordinar estas transiciones de manera sencilla y eficiente, creando animaciones más fluidas y visualmente atractivas.

Si deseas aprender más sobre transiciones en SwiftUI te recomiendo el artículo sobre cómo agregar transiciones entre vistas usando MatchGeometryEffect en SwiftUI.

Comparte este artículo

Subscríbete a nuestro Newsletter

Mantente al día en el mundo de las aplicaciones móviles con nuestro blog especializado.

Artículos semanales

Todas las semanas artículos nuevos sobre el mundo de las aplicaciones móviles.

No spam

No te enviaremos spam, solo contenido de calidad. Puedes darte de baja cuando quieras.

Contenido de calidad

Nada de contenido generado de manera automática usando ChatGPT.

Recomendaciones

Tips indispensables sobre mejores prácticas y metodologías.

© 2024 AsyncLearn