Limites de animação em Live Activity, Dynamic Island e widgets
Por equipe Charmotion · Atualizado em

Live Activities, a Dynamic Island e os widgets não conseguem tocar uma animação em loop contínua. Desde o iOS 17, eles animam mudanças de dados com transições e animações do SwiftUI, cada uma limitada a dois segundos, e nada se anima em telas Always-On. Para um personagem, troque poses estáticas com uma transição quando os dados mudarem, em vez de tocar Rive, Lottie, GIF ou vídeo.
Principais pontos
- Documentação do WidgetKit da Apple: "As animações em widgets e Live Activities têm duração máxima de dois segundos."
- Um engenheiro do DTS da Apple disse que animações contínuas na Dynamic Island e em widgets não são suportadas e chamou o truque da fonte de timer de gambiarra não suportada.
- Use
transition(_:),contentTransition(_:),animation(_:value:)eid(_:);Transactionnão está disponível. - Os dados de uma Live Activity são limitados a 4 KB, e uma atividade pode ficar ativa por até oito horas.
- Exporte poses estáticas do seu conjunto de animações e inclua-as como imagens na extensão do widget.
Uma Live Activity ou a Dynamic Island pode tocar uma animação de personagem em loop?
Não. Widgets e Live Activities são renderizados pelo sistema a partir da hierarquia de views SwiftUI no momento da atualização; seu código não roda um loop de renderização na Tela Bloqueada nem na Dynamic Island. As animações acontecem só como transição de um estado renderizado para o próximo.
Desenvolvedores perguntam sobre isso com frequência nos fóruns da Apple. Em um tópico sobre animar a Dynamic Island e widgets, um engenheiro do DTS da Apple respondeu que "existe uma gambiarra que alguns desenvolvedores descobriram, mas ela não é suportada pelo sistema e não pode ser recomendada", e que o tipo de animação contínua mostrado "não é suportado e pode drenar a bateria". A gambiarra em questão abusa de texto de timer com fontes personalizadas para simular frames; ela pode quebrar em qualquer versão.
Ou seja, um mascote não consegue ficar em idle, respirar ou piscar numa Live Activity. Ele pode mudar de pose, com uma transição animada curta, sempre que o seu app ou uma notificação push atualizar a atividade.

Quais animações widgets e Live Activities suportam?
O artigo da Apple "Animating data updates in widgets and Live Activities" lista o que funciona. Desde o iOS 17, widgets e Live Activities "suportam todas as transições e animações nativas do SwiftUI". Em versões anteriores do sistema, widgets não se animam, e Live Activities no iOS 16 ou anterior ignoram modificadores de animação e usam o timing do sistema, embora as transições nativas continuem valendo.
| Suportado | Não suportado |
|---|---|
| Transições de conteúdo padrão em texto, imagens e SF Symbols | Animações contínuas ou repetitivas |
transition(_:): opacity, move(edge:), slide, push(from:) e combinações | Transaction (então você não consegue cancelar animações com ela) |
contentTransition(_:), incluindo .numericText(countsDown:) | Animações com mais de dois segundos |
animation(_:value:) e springs | Qualquer animação no modo Always-On de baixa luminância |
id(_:) para animar uma view quando dados relacionados mudam | Rodar seu próprio loop de renderização ou timers |
Para desativar a animação de uma view, a Apple orienta passar .identity para transition(_:) ou nil para animation(_:value:).
O que é o limite de 2 segundos para animações?
Tanto a documentação do WidgetKit quanto a seção de Live Activities das Human Interface Guidelines indicam o mesmo limite: animações em widgets e Live Activities têm duração máxima de dois segundos, sejam do sistema ou personalizadas.
Na prática, projete cada transição para terminar bem dentro dessa janela. Uma spring com tempo de acomodação longo pode ser cortada; um .smooth(duration: 0.6) ou .spring(duration: 0.5, bounce: 0.3) fica com folga dentro dela. Se uma atualização muda várias views, a Apple sugere desativar a animação nas menos importantes para que a atenção vá para a mudança principal.
struct ScoreView: View {
let score: Int
var body: some View {
Text(score, format: .number)
.font(.title.monospacedDigit())
.contentTransition(.numericText())
.animation(.spring(duration: 0.5, bounce: 0.3), value: score)
}
}Posso reproduzir GIF, Lottie, Rive ou vídeo em um widget?
Não como reprodução. O mecanismo suportado são as próprias transições e animações do SwiftUI, renderizadas pelo sistema; não existe um ponto de integração para um player que avance frames ao longo do tempo. Rive e Lottie precisam de um loop de renderização ativo, e um widget ou Live Activity não oferece isso. A reprodução de GIF e vídeo também não faz parte do modelo de animação documentado, e o DTS já classificou a animação contínua como não suportada.
O que você pode fazer com esses arquivos é usar um frame deles. Exporte uma imagem estática para cada humor a partir dos vídeos do seu personagem e inclua as imagens no asset catalog da extensão do widget. Com o ffmpeg, um frame de um WebM com fundo transparente mantém o canal alfa se você decodificar com libvpx:
ffmpeg -c:v libvpx-vp9 -i happy.webm -ss 1.0 -frames:v 1 mascot-happy.png
ffmpeg -c:v libvpx-vp9 -i loading.webm -ss 1.0 -frames:v 1 mascot-loading.png
Os conjuntos do Charmotion nos planos pagos incluem versões em WebM e MOV transparentes de todas as 17 animações, então cada humor e reação está disponível como fonte para essas imagens estáticas. Redimensione-as para os tamanhos em pontos que você realmente exibe; a apresentação mínima da Live Activity, por exemplo, não deve passar de 45×36,67 pontos.
Quais são os limites de 4 KB de dados e de oito horas?
Da documentação do ActivityKit da Apple, "Displaying live data with Live Activities":
| Limite | Valor |
|---|---|
| Dados estáticos e dinâmicos por atualização (incluindo payloads de push) | 4 KB no total |
| Tempo ativo | Até oito horas |
| Tempo total na Tela Bloqueada | Até 12 horas (oito ativas mais até quatro depois do término) |
| Imagem da apresentação mínima | No máximo 45×36,67 pontos |
| Duração da animação | Máximo de dois segundos |
O limite de 4 KB é o motivo pelo qual imagens nunca vão no payload. Envie um valor pequeno, como um índice de humor, e busque uma imagem incluída no app:
import ActivityKit
struct DeliveryAttributes: ActivityAttributes {
struct ContentState: Codable, Hashable {
var mood: Int // 0 idle, 5 loading, 1 happy ...
var minutesLeft: Int
}
var orderNumber: String
}
As HIG acrescentam que as Live Activities são adequadas para tarefas que não passam de oito horas e que, depois que uma atividade termina, 15 a 30 minutos na Tela Bloqueada bastam na maioria dos casos.
O que acontece com a tela Sempre Ativa?
Em aparelhos com tela Sempre Ativa, a Apple diz que "o sistema não executa animações para preservar a bateria no modo Sempre Ativo". Verifique o valor de ambiente isLuminanceReduced (iOS 16 ou posterior) e adapte: pule a transição e mostre uma pose mais simples e escura.
struct MascotPose: View {
@Environment(\.isLuminanceReduced) private var isLuminanceReduced
let mood: Int
var body: some View {
Image("mascot-mood-\(mood)")
.resizable()
.scaledToFit()
.opacity(isLuminanceReduced ? 0.6 : 1)
.id(mood)
.transition(isLuminanceReduced ? .identity : .push(from: .bottom))
}
}
Mantenha a arte de baixa luminância simples: áreas grandes e claras ficam agressivas em uma Tela Bloqueada escurecida.
Qual é a melhor alternativa a um mascote em loop em uma Live Activity?
Troca de poses. Trate cada humor como uma imagem estática e deixe o sistema animar entre elas quando o estado mudar. O padrão documentado pela Apple para animar uma view quando outros dados mudam é associar a view a esses dados com id(_:) e adicionar uma transição; aqui, o humor é a identidade:
import SwiftUI
import WidgetKit
struct DeliveryLockScreenView: View {
let state: DeliveryAttributes.ContentState
var body: some View {
HStack(spacing: 12) {
MascotPose(mood: state.mood)
.frame(width: 56, height: 56)
.accessibilityHidden(true)
VStack(alignment: .leading) {
Text("Arriving in")
.font(.caption)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(state.minutesLeft, format: .number)
.contentTransition(.numericText(countsDown: true))
Text("min")
}
.font(.title2.bold())
}
}
.padding()
}
}
Cada atualização gera então um movimento curto e significativo: o personagem entra com uma nova pose enquanto os minutos diminuem. Associe os humores às fases da atividade (preparando → pose loading, a caminho → happy, atrasado → sad, entregue → uma pose success) e você terá um personagem que parece vivo sem quebrar as regras da plataforma. No app completo, use o personagem animado de verdade; é lá que entra a versão com movimento completo.

Perguntas frequentes
Posso animar a Dynamic Island com o truque da fonte de timer?
Já foi feito, mas um engenheiro do DTS da Apple disse que a abordagem não é suportada pelo sistema, não pode ser recomendada e que animações contínuas podem consumir bateria. Ela pode parar de funcionar em qualquer atualização do iOS. Use transições suportadas entre atualizações de dados.
Widgets têm animação no iOS 16?
Não. A documentação da Apple diz que, em versões do sistema anteriores ao iOS 17, widgets não são animados. Live Activities no iOS 16 ignoram modificadores de animação como animation(_:value:) e usam o timing do sistema, mas transições nativas como opacity, move, slide e push continuam valendo.
Posso enviar uma imagem de mascote em um push de Live Activity?
Na prática, não. Todos os dados estáticos e dinâmicos da Live Activity, incluindo payloads de push, precisam caber em 4 KB no total. Inclua as imagens das poses na extensão do widget e envie só um valor pequeno, como um número de humor, que seleciona qual imagem mostrar.
Quanto tempo pode durar uma animação em widget ou Live Activity?
No máximo dois segundos. A documentação do WidgetKit da Apple e as Human Interface Guidelines de Live Activities afirmam que animações do sistema e personalizadas em widgets e Live Activities têm duração máxima de dois segundos. Mantenha springs e transições bem mais curtas para que não sejam cortadas no meio do movimento.
Respostas rápidas deste guia
Fontes
- Animating data updates in widgets and Live Activities, Apple
- Displaying live data with Live Activities, Apple
- Human Interface Guidelines: Live Activities, Apple
- How to use animation for Dynamic Island and widgets?, Apple Developer Forums
- numericText(countsDown:), Apple
- isLuminanceReduced, Apple