Como adicionar animação a um app iOS (SwiftUI e UIKit)
Por equipe Charmotion · Atualizado em

Para adicionar animação a um app iOS, envolva as mudanças de estado no withAnimation do SwiftUI para feedback de interface, use symbolEffect para ícones e adicione Lottie ou Rive pelo Swift Package Manager para arte criada por designers. Use o Rive quando um personagem precisa de estados, e AVPlayerLooper quando você só precisa de um clipe fixo.
Principais pontos
- A animação nativa do SwiftUI cobre a maior parte do feedback de interface:
withAnimation,.animation(_:value:)ePhaseAnimator/KeyframeAnimatorno iOS 17+. symbolEffect(iOS 17+) anima SF Symbols, incluindo símbolos personalizados, com um único modificador.- Instale o Lottie a partir do
lottie-spm, não do repositório principal de mais de 300 MB. - O
RiveRuntimedo Rive suporta iOS 14+ e permite que o código troque os estados de um personagem em tempo real. - Leia
accessibilityReduceMotione troque os loops por uma imagem estática quando estiver ativado.
Já tem um personagem ou logo? Veja seu personagem em telas reais de app: telas de splash, onboarding, carregamento e estado vazio. É grátis, roda no navegador e não envia nada.
Qual abordagem de animação usar no iOS?
Comece pelo que está se movendo e por quem criou. A maioria dos apps precisa de uma combinação de quatro abordagens:
| Você quer animar | Uso |
|---|---|
| Botões, mudanças de layout, sheets, toggles | withAnimation do SwiftUI ou UIView.animate do UIKit |
| Ícones | symbolEffect em SF Symbols (iOS 17+) |
| Um loop vetorial criado por designer: confete, um spinner, uma ilustração | Lottie |
| Um personagem que reage a eventos do app | Rive com uma state machine |
| Um clipe pré-renderizado que nunca muda | Vídeo com AVPlayerLooper |
As APIs nativas não aumentam o tamanho do app e acompanham o seu estado automaticamente. Elas também são as mais consistentes com o resto do iOS: springs, apresentações de sheets e efeitos de símbolo parecem nativos porque são as mesmas animações de sistema que os próprios apps da Apple usam. Recorra a um runtime de terceiros só quando a arte vier de uma ferramenta de design. O Lottie reproduz exportações do After Effects. O Rive reproduz arquivos do editor Rive e adiciona uma state machine, para que o seu código possa mandar um personagem passar de idle para loading e depois para success sem emendar clipes.

Como funcionam withAnimation e .animation() no SwiftUI?
O SwiftUI anima a diferença entre dois estados. Altere um valor dentro de withAnimation e toda view que depende dele interpola para a nova posição, tamanho ou opacidade:
struct ExpandingCard: View {
@State private var expanded = false
var body: some View {
RoundedRectangle(cornerRadius: 16)
.frame(height: expanded ? 240 : 120)
.onTapGesture {
withAnimation(.spring()) { expanded.toggle() }
}
}
}
A alternativa é o modificador .animation(_:value:), que anima uma view sempre que o valor informado muda. Use withAnimation quando uma ação deve animar várias views, e o modificador quando uma view deve sempre animar um valor específico.
Para movimentos com vários passos, o iOS 17 adicionou PhaseAnimator e KeyframeAnimator. Um phase animator percorre uma sequência de fases:
Image(systemName: "heart.fill")
.phaseAnimator([false, true]) { content, phase in
content.scaleEffect(phase ? 1.2 : 1.0)
}
Use KeyframeAnimator quando precisar de trilhas de tempo separadas para propriedades como escala, rotação e deslocamento. Ambos são bons para pequenos loops de atenção, não para personagens completos.
Como animar SF Symbols e views do UIKit?
No iOS 17 e posteriores, o modificador .symbolEffect anima qualquer SF Symbol. Os efeitos nativos da Apple incluem bounce, pulse, variable color, scale, appear, disappear e replace, e também funcionam em símbolos personalizados:
Image(systemName: "bell.fill")
.symbolEffect(.bounce, value: unreadCount)
O sino quica sempre que unreadCount muda. Essa é a forma mais barata de dar feedback a um ícone, porque não há nenhum asset para incluir no app.
No UIKit, a animação de views baseada em blocos ainda funciona e muitas vezes é tudo de que uma tela precisa:
UIView.animate(withDuration: 0.3) {
banner.alpha = 1
banner.transform = .identity
}
Use-a para fades, deslizamentos e mudanças de escala em views existentes. Para qualquer coisa desenhada por um designer, como uma ilustração ou um mascote, keyframes programados à mão em Swift ficam trabalhosos de alterar. É nesse ponto que um arquivo Lottie ou Rive é mais fácil de manter: o designer edita o arquivo, e o seu código só decide quando ele toca.
Como adicionar uma animação Lottie a um app iOS?
No Xcode, escolha File > Add Package Dependencies e digite https://github.com/airbnb/lottie-spm.git. A Airbnb recomenda esse pacote porque é um wrapper pequeno sobre binários pré-compilados, enquanto o repositório principal lottie-ios tem mais de 300 MB. Use a versão mais recente listada no README.
Desde a versão 4.3.0, o Lottie inclui uma LottieView nativa para SwiftUI. Adicione o .json exportado ao seu target e reproduza:
import SwiftUI
import Lottie
struct ConfettiView: View {
var body: some View {
LottieView(animation: .named("confetti"))
.looping()
.frame(width: 200, height: 200)
}
}
A mesma versão adicionou suporte a movimento reduzido. O Lottie é uma boa opção para um loop de carregamento, uma explosão de confete de sucesso ou uma ilustração de onboarding que toca do início ao fim. É menos adequado para um personagem que precisa mudar de comportamento no meio de um loop conforme o que o app está fazendo; é aí que as state machines do Rive ajudam.
Duas dicas práticas. Mantenha o arquivo exportado pequeno pedindo ao designer que evite imagens raster incorporadas onde vetores funcionam. E teste a animação em um aparelho mais antigo, já que máscaras e efeitos complexos do After Effects podem ser pesados de renderizar mesmo quando o arquivo é pequeno.
Como adicionar uma animação Rive e trocar seus estados?
Adicione https://github.com/rive-app/rive-ios com o Swift Package Manager (ou pod 'RiveRuntime'). O runtime da Apple suporta iOS 14+, tvOS 16+, macOS 13.1+ e visionOS. Arraste o .riv para o target do seu app.
Com a API legada, o RiveViewModel carrega o arquivo, escolhe uma state machine e oferece métodos para controlá-la:
import SwiftUI
import RiveRuntime
struct MascotView: View {
@StateObject private var mascot = RiveViewModel(
fileName: "character",
stateMachineName: "CharacterStateMachine"
)
var body: some View {
mascot.view()
.frame(width: 220, height: 220)
}
func startLoading() { mascot.setInput("mood", value: 5.0) }
func finished(ok: Bool) {
mascot.triggerInput(ok ? "success" : "error")
mascot.setInput("mood", value: 0.0)
}
}
Mantenha o view model em @StateObject para que ele sobreviva aos redesenhos. Os nomes dos inputs diferenciam maiúsculas de minúsculas e precisam corresponder ao arquivo.
O novo runtime do Rive para Apple abandona os inputs em favor do Data Binding. Em vez disso, você define propriedades do view model, por exemplo viewModelInstance.setValue(of: NumberProperty(path: "mood"), to: 5) e viewModelInstance.fire(trigger: TriggerProperty(path: "success")). Isso só funciona se o arquivo definir um view model. O guia de Rive no SwiftUI aborda os dois runtimes em detalhes.
Como reproduzir um clipe de vídeo em loop no SwiftUI?
Se a animação é um clipe fixo e pré-renderizado, como a revelação de um logo 3D, um vídeo é mais simples do que qualquer runtime. O AVPlayerLooper reproduz um item continuamente por meio de um AVQueuePlayer, e o VideoPlayer do SwiftUI (AVKit, iOS 14+) o exibe:
import SwiftUI
import AVKit
final class LoopingClip: ObservableObject {
let player = AVQueuePlayer()
private var looper: AVPlayerLooper?
init(name: String) {
guard let url = Bundle.main.url(forResource: name, withExtension: "mp4") else { return }
looper = AVPlayerLooper(player: player, templateItem: AVPlayerItem(url: url))
player.isMuted = true
player.play()
}
}
struct ClipView: View {
@StateObject private var clip = LoopingClip(name: "logo-reveal")
var body: some View { VideoPlayer(player: clip.player) }
}
Mantenha uma referência ao looper, senão o loop para. Um vídeo não reage a estados, e cada variação é mais um arquivo, então use-o para clipes, não para personagens interativos.
O VideoPlayer mostra controles de reprodução. Para um loop decorativo sem controles, hospede um AVPlayerLayer em um pequeno UIViewRepresentable. Se o clipe precisa de fundo transparente sobre a sua interface, exporte-o como HEVC com alfa em um .mov; o comparativo de formatos explica quando isso supera um GIF ou um arquivo Rive.
Como adicionar um mascote animado a um app iOS?
Trate o mascote como uma view do estado do seu app. Liste os momentos aos quais ele deve reagir, dê a cada um deles um estado no arquivo e mapeie seus eventos para eles em um só lugar:
- Loops para estados contínuos: idle, loading, listening, sleeping.
- Triggers para eventos pontuais: success, error, uma saudação no enter.
Na prática, mantenha um enum pequeno, como .idle, .loading e .done(Bool), no seu view model e traduza-o em chamadas de setInput e triggerInput. A state machine cuida das transições, então você nunca precisa controlar qual clipe está na tela.

Se você já tem um mascote ou logo, mas não tem um animador, o Charmotion transforma um personagem enviado em 17 animações, normalmente em poucos minutos; em todo plano pago, o conjunto inclui um .riv com um view model Character (um número mood de 0 a 9 e triggers como success e error), além de código SwiftUI tanto para o RiveViewModel clássico quanto para o novo runtime. Veja de quais estados um mascote precisa para planejar o conjunto.
Como manter as animações no iOS rápidas e acessíveis?
Algumas regras evitam que a animação gaste bateria ou exclua usuários:
- Anime poucas views ao mesmo tempo, não listas inteiras. Pare os loops quando a view sair da tela.
- Prefira vetores (SF Symbols, Lottie, Rive) para pequenas artes de interface e vídeo para clipes fotográficos ou em 3D.
- Inclua o arquivo de animação no app em vez de baixá-lo na primeira abertura, para que ele esteja pronto quando a tela aparecer.
Respeite Ajustes > Acessibilidade > Movimento > Reduzir Movimento. O SwiftUI expõe essa opção como um valor de ambiente que é atualizado em tempo real:
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
if reduceMotion {
Image("mascot-still").resizable().scaledToFit()
} else {
mascot.view()
}
}
Quando o movimento carrega significado, como carregamento ou sucesso, mantenha a informação disponível em texto ou em um anúncio de acessibilidade. O guia de movimento reduzido explica as regras da WCAG.
Adicionar animação a um app iOS
- Comece pelo SwiftUI. Use
withAnimationou.animation(_:value:)para feedback de interface esymbolEffectpara ícones. - Adicione um runtime, se necessário. No Xcode, adicione
https://github.com/airbnb/lottie-spm.gitpara Lottie ouhttps://github.com/rive-app/rive-iospara Rive. - Inclua o arquivo no app. Arraste o
.json,.rivou.mp4para o projeto e confirme que ele faz parte do target do app. - Exiba a animação. Use
LottieView(animation: .named("name")).looping(),RiveViewModel(fileName:stateMachineName:).view()ouVideoPlayer. - Conecte ao estado do app. Chame
setInputpara loops etriggerInputpara reações únicas quando o seu view model mudar. - Respeite o Reduzir Movimento. Leia
accessibilityReduceMotione mostre uma imagem estática quando o valor for verdadeiro.
Perguntas frequentes
Devo usar UIView.animate ou withAnimation?
Use withAnimation em views SwiftUI e UIView.animate em views UIKit. Os dois animam mudanças de propriedades em views existentes. A versão do SwiftUI anima todas as views que dependem do estado alterado, então você descreve o estado final em vez do frame de cada view. Apps mistos podem usar os dois, cada um na sua camada.
Qual é a diferença entre PhaseAnimator e KeyframeAnimator?
Os dois chegaram no iOS 17. O PhaseAnimator percorre uma lista de fases e anima a transição entre elas, o que funciona bem para pulsos simples e sequências de vários passos. O KeyframeAnimator dá a cada propriedade sua própria linha do tempo de keyframes, o que funciona bem para movimentos precisos em que escala, rotação e posição mudam em momentos diferentes.
Lottie ou Rive para um app iOS?
Use Lottie para loops vetoriais lineares, criados por designers e exportados do After Effects. Use Rive quando a animação precisa reagir ao estado do app, como um mascote que alterna entre idle, loading e success, porque a state machine cuida das transições dentro do próprio arquivo. Os dois são instalados com Swift Package Manager e funcionam no SwiftUI.
O Rive funciona com UIKit?
Sim. O RiveRuntime oferece suporte a SwiftUI e UIKit. No runtime legado, o RiveViewModel pode criar tanto uma view UIKit quanto uma view SwiftUI, e as mesmas chamadas setInput e triggerInput a controlam. A documentação do Rive para Apple cobre as duas configurações, então você pode combiná-las em um mesmo app.
Respostas rápidas deste guia
Fontes
- withAnimation(_:_:), Apple
- Wind your way through advanced animations in SwiftUI (WWDC23), WWDC Notes
- Animate symbols in your app (WWDC23), Apple
- lottie-ios, Airbnb (GitHub)
- lottie-ios 4.3.0 release notes, Airbnb (GitHub)
- Apple runtime, Rive
- AVPlayerLooper, Apple
- accessibilityReduceMotion, Apple