Lottie en SwiftUI: LottieView, reproducción y loop
Por el equipo de Charmotion · Actualizado el

Para usar Lottie en SwiftUI, agrega el paquete lottie-spm y escribe LottieView(animation: .named("idle")).looping(). Usa .playing(loopMode: .playOnce) para una reproducción única, .playbackMode(.playing(.fromProgress(0, toProgress: 1, loopMode: .loop))) para rangos y .animationDidFinish para reaccionar cuando termina. Lottie es compatible con iOS, macOS, tvOS y visionOS, pero no con watchOS.
Puntos clave
- Instálalo desde
https://github.com/airbnb/lottie-spm.git: según Airbnb, clonarlo ocupa menos de 500 KB, frente a más de 300 MB del repositorio principal. LottieViewes una vista de SwiftUI con modificadores encadenables:.looping(),.playing(loopMode:),.playbackMode(_:),.resizable().- Los marcadores con nombre permiten que un solo archivo contenga varios segmentos, que seleccionas con
.marker(_:loopMode:). - Si el archivo contiene un marcador "reduced motion", Lottie puede reproducirlo en su lugar cuando Reducir movimiento está activado.
- LottieView no tiene una máquina de estados con Data Binding; Rive encaja mejor para una mascota de marca que reacciona al estado de la app.
¿Cómo instalo Lottie con Swift Package Manager?
En Xcode, elige File → Add Package Dependencies e ingresa https://github.com/airbnb/lottie-spm.git. El README de Airbnb recomienda este repositorio contenedor para SwiftPM porque clonar el repositorio principal lottie-ios ocupa más de 300 MB, mientras que lottie-spm ocupa menos de 500 KB. Agrega la biblioteca Lottie al target de tu app y escribe import Lottie.
Coloca el JSON de tu animación (o el archivo .lottie) en el target de la app. LottieAnimation.named("idle") busca idle.json en el bundle principal de forma predeterminada.
El manifiesto de lottie-spm declara iOS, macOS, tvOS y visionOS. No incluye la plataforma watchOS, algo importante si compartes código de interfaz con una app de Watch.
¿Cómo muestro una LottieView en SwiftUI?
LottieView forma parte de lottie-ios desde la versión 4.3.0. La forma más sencilla:
import SwiftUI
import Lottie
struct LoadingMascot: View {
var body: some View {
LottieView(animation: .named("loading"))
.looping()
.resizable()
.scaledToFit()
.frame(width: 180, height: 180)
.accessibilityLabel("Loading")
}
}
.resizable() permite que la animación se escale a su marco como una Image redimensionable; sin él, la vista usa el tamaño intrínseco de la animación. Otros inicializadores son LottieView(dotLottieFile:) para archivos .lottie y variantes con closures asíncronos que cargan una animación (por ejemplo, desde una URL) y muestran un placeholder mientras carga.
Una nota sobre el costo: Lottie renderiza formas vectoriales en cada fotograma. Para una mascota pequeña en loop no hay problema; si tienes muchas animaciones simultáneas en una lista con scroll, usa una imagen estática en la lista y anima solo el elemento enfocado.
¿Cómo reproduzco una LottieView en loop o una sola vez?
Los modificadores de reproducción corresponden a LottiePlaybackMode:
// Loop forever
LottieView(animation: .named("idle")).looping()
// Play once and stop on the last frame
LottieView(animation: .named("success")).playing(loopMode: .playOnce)
// Play a progress range on loop
LottieView(animation: .named("idle"))
.playbackMode(.playing(.fromProgress(0, toProgress: 1, loopMode: .loop)))
// Paused on the current frame
LottieView(animation: .named("idle")).paused(at: .currentFrame)
Para reaccionar cuando termina una reproducción única, agrega .animationDidFinish { completed in … }. Para reiniciarla cuando quieras, controla el modo de reproducción desde el estado y cámbialo:
struct SaveButton: View {
@State private var playback: LottiePlaybackMode = .paused(at: .progress(0))
var body: some View {
VStack {
LottieView(animation: .named("success"))
.playbackMode(playback)
.animationDidFinish { _ in playback = .paused(at: .progress(0)) }
.frame(width: 120, height: 120)
Button("Save") {
playback = .playing(.fromProgress(0, toProgress: 1, loopMode: .playOnce))
}
}
}
}
Otros modos de loop son .autoReverse, .repeat(_:) y .repeatBackwards(_:).
¿Puedo cambiar de estado de ánimo en Lottie sin usar archivos separados?
Sí, con marcadores. Si el diseñador agrega marcadores con nombre en After Effects o Lottie Creator (por ejemplo idle, happy, sad), puedes reproducir un segmento a la vez:
enum Mood: String { case idle, happy, sad }
struct MarkerMascot: View {
let mood: Mood
var body: some View {
LottieView(animation: .named("mascot"))
.playbackMode(.playing(.marker(mood.rawValue, loopMode: .loop)))
.resizable()
.scaledToFit()
}
}
También existen .fromMarker(_:toMarker:loopMode:) y .markers([…]), que reproduce varios marcadores en secuencia, útil para "reaccionar y luego volver a la calma".
La limitación está en las transiciones. Al cambiar de marcador, la reproducción salta al nuevo segmento en el punto en que estuviera el anterior; nada se mezcla, a menos que el arte esté diseñado para que cada segmento empiece y termine en la misma pose. Ese es justo el trabajo que una máquina de estados (state machine) hace por ti.
¿Cómo maneja LottieView la opción Reducir movimiento (Reduce Motion)?
Lottie 4.3.0 agregó compatibilidad con movimiento reducido. Si una animación contiene un marcador llamado reduced motion (el código fuente también acepta reducedMotion, reduced_motion y reduced-motion), Lottie reproduce ese marcador en lugar de la animación completa cuando la opción de movimiento reducido está activa. De forma predeterminada, sigue la configuración del sistema.
Si tu archivo no tiene ese marcador, gestiónalo tú mismo:
struct AdaptiveLottie: View {
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
LottieView(animation: .named("idle"))
.playbackMode(reduceMotion ? .paused(at: .progress(0)) : .playing(.fromProgress(0, toProgress: 1, loopMode: .loop)))
.resizable()
.scaledToFit()
}
}
Elige un fotograma de pausa que funcione bien como pose fija; el fotograma 0 suele ser una pose neutra, pero no siempre. Más patrones: Reduce Motion en SwiftUI y UIKit.
¿Cómo controlo un LottieView desde el estado de la app?
Deja la decisión en tu modelo y que la vista elija la animación. Un enum pequeño mantiene los nombres de archivo en un solo lugar y hace explícitas las reacciones puntuales:
enum UploadState: Equatable {
case idle, uploading, done, failed
var animationName: String {
switch self {
case .idle: return "idle"
case .uploading: return "loading"
case .done: return "success"
case .failed: return "error"
}
}
var loopMode: LottieLoopMode {
switch self {
case .idle, .uploading: return .loop
case .done, .failed: return .playOnce
}
}
}
struct UploadMascot: View {
let state: UploadState
var body: some View {
LottieView(animation: .named(state.animationName))
.playing(loopMode: state.loopMode)
.resizable()
.scaledToFit()
.id(state) // new view per state, so each clip starts from frame 0
.transition(.opacity)
.animation(.easeInOut(duration: 0.2), value: state)
}
}
.id(state) fuerza una vista nueva cuando cambia el estado, lo que reinicia la reproducción desde el principio y permite que un crossfade breve disimule el corte. Sin esto, SwiftUI puede reutilizar la vista y conservar el progreso de la animación anterior. Si prefieres un solo archivo con marcadores, reemplaza el nombre de la animación por .playbackMode(.playing(.marker(…, loopMode:))), como se muestra arriba.
Aquí también se hacen visibles los límites de Lottie para personajes: estás escribiendo la máquina de estados tú mismo, un switch a la vez.
¿Qué plataformas admite Lottie?
| Plataforma | lottie-spm | RiveRuntime |
|---|---|---|
| iOS | Yes | 14.0+ |
| macOS | Yes | 13.1+ |
| tvOS | Yes | 16.0+ |
| visionOS | Yes | 1.0+ |
| watchOS | No declarado | No declarado |
Revisa la lista platforms en cada Package.swift para conocer el mínimo exacto de la versión que fijes, ya que cambia entre versiones. Ninguno de los dos paquetes declara watchOS, así que en Apple Watch necesitas animadores de SwiftUI o fotogramas prerenderizados; consulta Animación de personajes en watchOS y visionOS.
En visionOS, LottieView funciona dentro de una ventana normal de SwiftUI exactamente igual que en iPhone. En macOS, el mismo código de SwiftUI compila, y las apps de AppKit pueden usar LottieAnimationView directamente. Para pantallas de UIKit en iOS, LottieAnimationView es la clase de vista que hay detrás de LottieView; expone play(), loopMode y animationSpeed como propiedades y métodos.
¿Cuándo conviene elegir Rive en lugar de Lottie para una mascota de marca?
| Lottie (LottieView) | Rive | |
|---|---|---|
| Formato | JSON o .lottie, normalmente desde After Effects o Lottie Creator | Archivo binario .riv desde el editor de Rive |
| Cambiar de estado desde el código | Elegir un archivo, un marcador o un rango de progreso | Asignar un número o disparar un trigger; la máquina de estados hace la transición |
| Mezcla entre estados | Diseñada a mano; si no, hay cortes | Integrada en las transiciones de la máquina de estados |
| Datos bidireccionales | No | Propiedades de Data Binding y streams de triggers |
| Ideal para | Clips fijos: indicadores de carga, checks de éxito, ilustraciones | Personajes que reaccionan a la app |
Muchas apps usan ambos: Lottie para algunos clips decorativos y Rive para la mascota. Un personaje de Rive con un número mood y triggers reemplaza lo que, de otro modo, sería una carpeta de archivos de Lottie más la lógica para cambiar entre ellos. Consulta Lottie vs Rive: máquinas de estados para una comparación más a fondo.
Agrega una animación de Lottie en loop a una vista de SwiftUI
- Agrega el paquete. En Xcode, agrega
https://github.com/airbnb/lottie-spm.gity vincula la bibliotecaLottie. - Incluye el archivo en el bundle. Agrega
idle.json(o un archivo .lottie) al target de la app. - Muéstrala. Escribe
LottieView(animation: .named("idle")).looping().resizable().scaledToFit()con un frame. - Gestiona las reacciones puntuales. Usa
.playing(loopMode: .playOnce)y.animationDidFinish, o controla.playbackModedesde el estado. - Respeta Reducir movimiento. Agrega un marcador "reduced motion" al archivo, o pausa en un fotograma fijo cuando
accessibilityReduceMotionsea true.
Preguntas frecuentes
¿Por qué usar lottie-spm en lugar del repositorio lottie-ios?
Ambos te dan la misma biblioteca de Lottie. Airbnb recomienda lottie-spm para Swift Package Manager porque clonar el repositorio principal lottie-ios supera los 300 MB, mientras que lottie-spm pesa menos de 500 KB, lo que hace que la resolución de paquetes sea mucho más rápida en Xcode y en CI.
¿LottieView funciona en iOS 13 o 14?
Revisa la lista de plataformas en el Package.swift de lottie-spm para la versión que fijes, porque los mínimos cambian entre versiones. LottieView llegó en lottie-ios 4.3.0. Si tu deployment target es inferior al que declara el paquete, Xcode se niega a resolverlo para ese target.
¿LottieView puede reproducir un archivo .lottie (dotLottie)?
Sí. LottieView tiene un inicializador que recibe un DotLottieFile, además de una variante asíncrona que lo carga y muestra un placeholder mientras tanto. dotLottie es un contenedor comprimido que puede incluir varias animaciones y sus imágenes en un solo archivo, que suele pesar menos que el JSON equivalente y mantiene los recursos juntos.
Respuestas rápidas de esta guía
Fuentes
- lottie-ios, Airbnb (GitHub)
- LottieView.swift, Airbnb (GitHub)
- LottiePlaybackMode.swift, Airbnb (GitHub)
- lottie-spm Package.swift, Airbnb (GitHub)
- lottie-ios 4.3.0 release notes, Airbnb (GitHub)
- Lottie for iOS documentation, Airbnb
- rive-ios Package.swift, Rive (GitHub)