Pular para o conteúdo
charmotion

Como adicionar animação a um app iOS (SwiftUI e UIKit)

Por equipe Charmotion · Atualizado em

Ilustração de capa do guia: Como adicionar animação a um app iOS (SwiftUI e UIKit), com personagens de demonstração do Charmotion

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:) e PhaseAnimator/KeyframeAnimator no 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 RiveRuntime do Rive suporta iOS 14+ e permite que o código troque os estados de um personagem em tempo real.
  • Leia accessibilityReduceMotion e 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 animarUso
Botões, mudanças de layout, sheets, toggleswithAnimation do SwiftUI ou UIView.animate do UIKit
ÍconessymbolEffect em SF Symbols (iOS 17+)
Um loop vetorial criado por designer: confete, um spinner, uma ilustraçãoLottie
Um personagem que reage a eventos do appRive com uma state machine
Um clipe pré-renderizado que nunca mudaVí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.

Tabela de decisão: APIs nativas para feedback de interface, efeitos de ícone para ícones, uma state machine do Rive para personagens, vídeo para clipes de marketing
Escolha o método de animação conforme a tarefa.

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.

Quatro telas de celular usando um mascote para carregamento, caixa de entrada vazia, pagamento concluído e upload com falha
Um mascote nos quatro estados mais comuns de um app.

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

  1. Comece pelo SwiftUI. Use withAnimation ou .animation(_:value:) para feedback de interface e symbolEffect para ícones.
  2. Adicione um runtime, se necessário. No Xcode, adicione https://github.com/airbnb/lottie-spm.git para Lottie ou https://github.com/rive-app/rive-ios para Rive.
  3. Inclua o arquivo no app. Arraste o .json, .riv ou .mp4 para o projeto e confirme que ele faz parte do target do app.
  4. Exiba a animação. Use LottieView(animation: .named("name")).looping(), RiveViewModel(fileName:stateMachineName:).view() ou VideoPlayer.
  5. Conecte ao estado do app. Chame setInput para loops e triggerInput para reações únicas quando o seu view model mudar.
  6. Respeite o Reduzir Movimento. Leia accessibilityReduceMotion e 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

Guias relacionados