Pular para o conteúdo
charmotion

Animação de personagens no watchOS e visionOS

Por equipe Charmotion · Atualizado em

Ilustração de capa do guia de iOS e Swift: animação de personagem no watchOS e no visionOS, com personagens de demonstração do Charmotion

Nem Rive nem Lottie têm suporte oficial ao watchOS: o rive-ios declara iOS, visionOS, tvOS, macOS e Mac Catalyst, e o lottie-spm declara iOS, macOS, tvOS e visionOS. No Apple Watch, anime com PhaseAnimator ou KeyframeAnimator do SwiftUI (watchOS 10+) ou reproduza frames pré-renderizados. No visionOS, os dois funcionam em uma janela SwiftUI comum.

Principais pontos

  • Package.swift do rive-ios: iOS 14, visionOS 1, tvOS 16, macOS 13.1, Mac Catalyst 14. Sem watchOS.
  • O Package.swift do lottie-spm lista iOS, macOS, tvOS e visionOS. Sem watchOS.
  • No watchOS, use os animators do SwiftUI ou uma sequência de frames controlada por TimelineView.
  • No visionOS, um mascote 2D fica em uma janela ou ornament do SwiftUI; o RealityKit é para modelos 3D.
  • Exporte os frames do vídeo com fundo transparente do mesmo personagem para que Watch, celular e Vision Pro fiquem iguais.

O Rive tem suporte ao watchOS?

Não oficialmente. As plataformas no Package.swift do rive-ios são:

platforms: [.iOS("14.0"), .visionOS("1.0"), .tvOS("16.0"), .macOS("13.1"), .macCatalyst("14.0")]

O Swift Package Manager não vincula o pacote a um target watchOS porque o watchOS não está nessa lista. Um resumo da página de migração do Rive para Apple já deu a entender, em alguns momentos, que o novo runtime suporta watchOS, mas é o manifesto publicado que o Xcode aplica, então planeje como se o Rive não estivesse disponível no Watch. Confira o manifesto de novo ao atualizar o pacote, já que as listas de plataformas podem mudar entre versões.

O mesmo vale para o runtime legado do Rive: os dois runtimes vêm em um único pacote com um único conjunto de plataformas. Se o seu app de iPhone e o app do Watch compartilham um pacote Swift de componentes de UI, mantenha as views que usam Rive em um módulo do qual só os targets iOS (e visionOS) dependem, ou o build do Watch não vai conseguir resolver a dependência.

O Lottie tem suporte ao watchOS?

Não. O manifesto do lottie-spm, que a Airbnb recomenda para o Swift Package Manager, declara iOS, macOS, tvOS e visionOS. Não há entrada para watchOS.

OpçãoiOSvisionOSwatchOS
RiveRuntime (rive-ios)14.0+1.0+Não declarado
Lottie (lottie-spm)YesYesNão declarado
SwiftUI PhaseAnimator / KeyframeAnimator17.0+1.0+10.0+
Sequência de frames com TimelineView do SwiftUIYesYesYes
AVKit VideoPlayerYesYesYes

Para as versões mínimas exatas do Lottie, leia a linha platforms da versão que você fixar.

Existem forks antigos e ports da comunidade do Lottie para watchOS, mas eles não são o pacote da Airbnb e a manutenção varia. Para um app que você pretende continuar atualizando, as opções nativas das linhas de baixo são a escolha de menor risco: vêm com o sistema, seguem as configurações de acessibilidade e não exigem dependência extra no target do Watch.

O que posso usar no Apple Watch no lugar?

Três opções, da mais leve à mais pesada:

  1. Animators do SwiftUI sobre uma imagem estática. phaseAnimator e keyframeAnimator estão disponíveis a partir do watchOS 10. Um quique, inclinação ou pulsação em uma única pose não exige nenhum arquivo além de uma imagem. Veja PhaseAnimator vs KeyframeAnimator.
  2. Uma sequência de frames. Exporte um loop curto como PNGs numerados, adicione-os ao asset catalog do app do Watch e percorra-os com TimelineView. Isso mantém o movimento real do personagem (piscadas, acenos) em troca de um app maior.
  3. Vídeo. O VideoPlayer do AVKit para SwiftUI está disponível no watchOS. Ele mostra os controles do player e serve mais para um clipe que o usuário escolhe assistir do que para um mascote de ambiente.

Uma view com sequência de frames:

import SwiftUI

struct FrameSequence: View {
    let frames: [String]          // ["wave_00", "wave_01", ...] in the asset catalog
    var fps: Double = 12
    @Environment(\.accessibilityReduceMotion) private var reduceMotion

    var body: some View {
        if reduceMotion || frames.count < 2 {
            Image(frames.first ?? "")
                .resizable()
                .scaledToFit()
        } else {
            TimelineView(.animation(minimumInterval: 1 / fps)) { context in
                let tick = Int(context.date.timeIntervalSinceReferenceDate * fps)
                Image(frames[tick % frames.count])
                    .resizable()
                    .scaledToFit()
            }
        }
    }
}

// Usage
FrameSequence(frames: (0..<24).map { String(format: "wave_%02d", $0) })
    .frame(width: 80, height: 80)

Mantenha os loops curtos e leves: a tela do Watch é minúscula e cada frame aumenta o app. Reproduza a sequência em um momento específico (um treino concluído, um lembrete) em vez de deixá-la em loop o dia todo.

Como exporto frames para watchOS a partir do meu conjunto de animações?

Comece de uma fonte com fundo transparente para que o personagem fique limpo sobre o fundo preto do Watch. Com ffmpeg e um WebM VP9 com canal alfa:

# 12 fps, 160 px wide, keep transparency
ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.png

Depois, arraste os PNGs para o asset catalog do target do Watch. Dicas:

  • Dimensione para a tela. Exporte no maior tamanho em pontos que você exibe multiplicado pela escala da tela, não na resolução da fonte.
  • Encurte o loop. Um loop de dois segundos a 12 fps tem 24 imagens; muitas vezes isso basta para um idle ou um wave.
  • Escolha uma imagem estática para Reduzir Movimento. O primeiro frame serve também como pose estática.

Os conjuntos do Charmotion nos planos pagos incluem arquivos WebM transparentes e MOV HEVC com alfa para cada animação, junto com o .riv usado no iPhone, então os frames do Watch vêm exatamente do mesmo movimento do app do celular.

Como compartilhar uma view de mascote entre iPhone, Watch e Vision Pro?

Esconda a diferença entre plataformas atrás de uma única view que recebe o mesmo input em todo lugar, por exemplo o número de mood. O ramo de iOS e visionOS usa Rive; o ramo de watchOS usa frames:

import SwiftUI
#if !os(watchOS)
import RiveRuntime
#endif

struct Mascot: View {
    let mood: Int

    var body: some View {
        #if os(watchOS)
        FrameSequence(frames: Self.frames(for: mood))
        #else
        RiveMascot(mood: mood)       // wraps RiveUIViewRepresentable and setValue(of:to:)
        #endif
    }

    #if os(watchOS)
    static func frames(for mood: Int) -> [String] {
        (0..<24).map { String(format: "mood%d_%02d", mood, $0) }
    }
    #endif
}

Adicione o pacote rive-ios apenas aos targets de iOS e visionOS, e as imagens de frames apenas ao target do Watch, para que nenhuma plataforma carregue os assets da outra. O código compartilhado (seu model, o enum de mood) continua independente de plataforma.

O Rive roda no visionOS?

Sim. O visionOS 1.0 está na lista de plataformas do rive-ios, e o manifesto do Lottie também inclui o visionOS. No Vision Pro, um app SwiftUI mostra suas views em janelas, então o mesmo código que você usa no iPhone funciona:

import SwiftUI
import RiveRuntime

struct MascotWindow: View {
    @StateObject private var model = CharacterModel()   // loads the .riv and keeps the view model instance

    var body: some View {
        RiveUIViewRepresentable(rive: model.rive)
            .frame(width: 320, height: 320)
            .padding(32)
            .glassBackgroundEffect()
            .task { await model.load() }
    }
}

CharacterModel aqui é o controlador de Data Binding do Rive em SwiftUI: ele cria o Worker, o File, a instância do view model e a state machine vinculada. glassBackgroundEffect() é o material de vidro do visionOS; deixe de fora nas outras plataformas.

Teste no dispositivo, além do simulador. A renderização é baseada em Metal nos dois runtimes, e o peso visual de um personagem plano flutuando em um ambiente é difícil de avaliar na tela de um Mac.

No visionOS, um mascote 2D deve ficar em uma janela SwiftUI ou no RealityKit?

Mantenha um personagem 2D no SwiftUI. RealityKit e Reality Composer Pro foram feitos para conteúdo 3D: modelos, materiais e animação por esqueleto. Um personagem plano de Rive ou Lottie colocado no RealityKit não ganha nada e perde a API simples baseada em views.

PosicionamentoUse para
Dentro da janela principalOnboarding, estados vazios, avatar de assistente: igual ao iPhone
Ornament preso a uma janelaUm pequeno ajudante fixo ao lado do seu conteúdo
Janela pequena separadaUm companheiro que o usuário pode mover de lugar
Entidade do RealityKitSó se o personagem for um modelo 3D de verdade

O Reduzir Movimento importa ainda mais em um headset, onde o movimento ocupa uma parte maior do campo de visão. Leia @Environment(\.accessibilityReduceMotion) (disponível no visionOS 1) e pause ou troque por uma pose parada; veja Reduzir Movimento em SwiftUI e UIKit.

Adicione uma animação de personagem a um app de Apple Watch

  1. Escolha o método. Use um animador do SwiftUI sobre uma pose parada para movimentos simples, ou uma sequência de frames para movimento real de personagem.
  2. Exporte os frames. Rode ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.png em um WebM com fundo transparente.
  3. Adicione ao target do Watch. Arraste os PNGs para o asset catalog do app do Watch.
  4. Reproduza. Alterne as imagens com TimelineView(.animation(minimumInterval:)) na taxa de frames da exportação.
  5. Trate o Reduzir Movimento. Mostre o primeiro frame como imagem parada quando accessibilityReduceMotion for verdadeiro.

Perguntas frequentes

Posso compartilhar o código da minha view Rive de iOS com um target watchOS?

Não diretamente, porque o pacote RiveRuntime não declara watchOS e não é vinculado a um target do Watch. Envolva o mascote em uma view sua com condicionais de plataforma: Rive no iOS e no visionOS, uma sequência de frames ou um animador do SwiftUI no watchOS, todos alimentados pelo mesmo valor de mood.

Um GIF roda no Apple Watch?

O Image do SwiftUI não anima GIFs em nenhuma plataforma Apple. Decodifique os frames do GIF em imagens e alterne entre elas, ou, melhor ainda, exporte frames PNG de uma fonte com fundo transparente e reproduza com TimelineView. Assim você controla a taxa de frames, o tamanho e o Reduzir Movimento.

O Lottie está disponível no visionOS?

Sim. O manifesto do lottie-spm declara visionOS junto com iOS, macOS e tvOS, então o LottieView funciona em uma janela SwiftUI do visionOS do mesmo jeito que no iPhone. O pacote do Rive também declara visionOS 1.0, então os dois runtimes são opções para um personagem 2D em uma janela ou ornament do visionOS.

Respostas rápidas deste guia

Fontes

Guias relacionados