Aplicar transición de zoom al navegar entre vistas
Misael Cuevas
07 agosto, 20246min de lectura
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// 1struct ContentView: View {var body: some View {// 2NavigationStack {// 3NavigationLink("👉 Tap Me 👈") {// 4Text("Hello world")}}}}
- Se define ContentView como vista principal.
- Se define un tipo de navegación en stack (pila).
- Se establece un
NavigationLink
que, al ser presionado, navega desde ContentView a la vista de destino. - Se muestra un
Text
como la vista de destino.
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:
nonisolatedfunc navigationTransition(_ style: some NavigationTransition) -> some View
El modificador tiene el parámetro style
, donde se especifica el estilo de transición deseado. Estos son:
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.zoom(sourceID: some Hashable, in namespace: Namespace.ID)
: Aplica una transición de tipo zoom. Tiene los parámetrossourceID
para establecer un identificador desde donde se originó la transición (veremos su utilidad más adelante) ynamespace
para indicar dónde está definido elsourceID
.
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))
¡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:
nonisolatedfunc matchedTransitionSource(id: some Hashable,in namespace: Namespace.ID) -> some View
Este modificador tiene dos parámetros:
id
: El identificador origen de la transición.namespace
: Indica dónde está definido el id.
Agrega el modificador al NavigationLink
del código de ejemplo:
.matchedTransitionSource(id: 1, in: namespace)
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 SwiftUIstruct ContentView: View {@Namespace var namespacevar 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// 1struct Pet: Identifiable, Hashable {let id = UUID()let name: Stringlet emoji: String}struct PetsView: View {@Namespace var namespacelet pets = [Pet(name: "Dog", emoji: "🐶"),Pet(name: "Cat", emoji: "🐱"),Pet(name: "Bird", emoji: "🦜")]var body: some View {NavigationStack {List(pets) { pet inNavigationLink(pet.name, value: pet)// 2.matchedTransitionSource(id: pet.id, in: namespace)}.navigationDestination(for: Pet.self) { pet inText(pet.emoji).navigationTransition(// 3.zoom(sourceID: pet.id, in: namespace))}}}}
- Se define la estructura Pet para mostrar un listado de mascotas. Posee la propiedad
id
como identificador único a utilizar en los modificadoresnavigationTransition
ymatchedTransitionSource
. - Por cada
pet
del listado se asigna suid
enmatchedTransitionSource
. - Se establece el
id
de la mascota comosourceId
dezoom
.
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:
nonisolatedfunc 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.