Transition é um mecanismo de mudança visual que substitui um conteúdo por outro: telas, fragmentos, views ou estados de interface. Uma transição bem implementada direciona a atenção do usuário, explica a relação entre elementos e torna a navegação intuitiva. De acordo com as Material Design Guidelines (2026), aplicativos com transições bem projetadas mostram 22% mais retenção de usuários na segunda sessão. Saiba mais sobre outros tipos de animação no guia geral de animação.
Principais conclusões
Transition é uma animação que ocorre ao substituir um estado de interface visual por outro. Ao contrário da Property Animation (animar uma propriedade de um único objeto), Transition gerencia um conjunto completo de mudanças: aparecimento/desaparecimento de elementos, alteração de sua posição, tamanho e propriedades em uma única transição. Transition resolve o problema da mudança suave de conteúdo para que o usuário entenda o que se moveu para onde.
Em plataformas móveis, Transition é usado em três cenários principais: navegação entre telas (push, pop, modal present), mudança de fragmentos (FragmentTransaction do Android) e mudança de estado dentro da tela (expansão de cartão, alternância de abas). Cada cenário exige sua própria abordagem: transições de navegação — UIViewControllerAnimatedTransitioning no iOS ou ActivityOptions no Android, transições dentro da tela — Transition Framework ou UIView.transition.
De acordo com a Apple HIG (2026), a duração de uma transição padrão não deve exceder 400–500 ms — animações mais longas são percebidas como atraso. O Material Design recomenda 300–350 ms para transições móveis. Para elementos grandes (cartões, imagens), o tempo pode aumentar para 500–600 ms sem perda percebida de desempenho.
Tipos de transição são divididos em várias categorias dependendo de qual conteúdo muda e como. Tipos básicos: cross-fade — desaparecimento suave de um e aparecimento de outro; slide — uma tela sai, outra entra; scale/zoom — um elemento aumenta, abrindo uma tela de detalhes. Transições combinadas misturam vários efeitos.
| Tipo de transição | Descrição | API iOS | API Android |
|---|---|---|---|
| Cross-fade | Desaparecimento: um conteúdo desaparece, outro aparece | UIView.transition(with:duration:options:.transitionCrossDissolve) | TransitionSet + Fade() |
| Slide | Deslizamento: conteúdo entra/sai horizontal ou verticalmente | CATransition(type: .push, subtype: .fromLeft) | Slide() / FragmentTransaction.setCustomAnimations |
| Scale / Zoom | Escala: elemento amplia para tela cheia | UIViewPropertyAnimator com animação de escala | Scale() + ActivityOptions.makeScaleUpAnimation |
| Explode | Explosão: conteúdo se fragmenta ao desaparecer | CATransition(type: .reveal) | Explode() (API 21+) |
| Fade-through | Desaparecimento através de tela branca/preta | UIView.transition(with: .transitionCrossDissolve, com fundo branco) | Fade() via ChangeBounds |
Regras do Material Design: use um tipo de transição dentro de um único aplicativo para criar uma linguagem visual unificada. Recomendado: slide para navegação entre telas do mesmo nível (master → detalhe), cross-fade para mudança de conteúdo dentro de uma tela (abas, alternância de visualização), scale/zoom para transição de um cartão para uma tela de detalhes (cartão de produto → descrição).
No iOS, UIView.transition é a maneira mais simples de animar mudanças de conteúdo dentro de uma única View. Ele suporta cross-dissolve, curl-up, curl-down, flip-from-left, flip-from-right. Para transições de navegação entre UIViewController, use UINavigationControllerDelegate com UIViewControllerAnimatedTransitioning — isso dá controle total sobre a animação push/pop.
import UIKit
// UIView.transition: troca de imagem com cross-dissolve
UIView.transition(with: imageView,
duration: 0.4,
options: [.transitionCrossDissolve, .curveEaseInOut]
) {
self.imageView.image = UIImage(named: "new_image")
} completion: { _ in
print("Transition completed")
}
// UIView.transition: troca de duas views
UIView.transition(from: firstView, to: secondView,
duration: 0.5,
options: [.transitionFlipFromRight, .showHideTransitionViews]
) { _ in
// firstView oculta, secondView exibida
}
// CATransition para camada (sem Auto Layout)
let transition = CATransition()
transition.type = .push
transition.subtype = .fromRight
transition.duration = 0.35
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
view.layer.add(transition, forKey: "pushTransition")
UIViewPropertyAnimator é uma alternativa moderna para transições personalizadas no iOS 10+. Ao contrário do UIView.transition, o PropertyAnimator suporta pausa, cancelamento e animação reversa, o que é importante para transições interativas (deslizar para voltar). Para animação entre UIViewControllers, use UIPercentDrivenInteractiveTransition junto com PropertyAnimator — este é o padrão padrão para navegação interativa.
No Android, FragmentTransaction com setCustomAnimations é a principal maneira de animar transições entre Fragment. Parâmetros: enter (animação de entrada do novo Fragment), exit (animação de saída do Fragment antigo), popEnter e popExit — para navegação de retorno. FragmentTransaction suporta recursos de animação (R.anim) e Transition Framework (R.transition).
import androidx.fragment.app.FragmentTransaction
import androidx.transition.TransitionInflater
// FragmentTransaction com animações de recursos
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.slide_in_right, // enter
R.anim.slide_out_left, // exit
R.anim.slide_in_left, // popEnter
R.anim.slide_out_right // popExit
)
.replace(R.id.container, DetailFragment())
.addToBackStack(null)
.commit()
// FragmentTransaction com Transition Framework
val detailFragment = DetailFragment()
detailFragment.enterTransition = TransitionInflater.from(this)
.inflateTransition(R.transition.slide_right)
detailFragment.exitTransition = TransitionInflater.from(this)
.inflateTransition(R.transition.fade_out)
supportFragmentManager.beginTransaction()
.replace(R.id.container, detailFragment)
.addToBackStack(null)
.commit()
// ActivityOptions: animação ao iniciar uma Activity
val options = ActivityOptions.makeScaleUpAnimation(
view, 0, 0, view.width, view.height
).toBundle()
startActivity(intent, options)
Melhores práticas do Android: Slide() — para substituição de Fragment na navegação (enter = Slide(Gravity.END), exit = Slide(Gravity.START)). Fade() — para mostrar/esconder sobreposições e diálogos. Explode() — para transições de destaque (excluir um item de uma lista). Para dispositivos antigos (API < 21) use recursos R.anim como fallback. Transition Framework não suporta SurfaceView, TextureView, GLSurfaceView — para vídeo e câmera use apenas animações R.anim.
UIViewControllerAnimatedTransitioning é um protocolo iOS para criar animações de transição totalmente personalizadas entre controladores. Ele fornece acesso à view contentora (transitionContext.containerView), à view de origem e à view de destino. Combinado com UIPercentDrivenInteractiveTransition, esta abordagem permite criar transições interativas com rolagem por toque.
import UIKit
"> Animador de transição personalizado
class ScaleTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let isPresenting: Bool
init(presenting: Bool) { self.isPresenting = presenting }
func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.4
}
func animateTransition(using ctx: UIViewControllerContextTransitioning) {
guard let toView = ctx.view(forKey: .to),
let fromView = ctx.view(forKey: .from)
else { return }
let container = ctx.containerView
let initialScale: CGAffineTransform = CGAffineTransform(scaleX: 0.8, y: 0.8)
let finalFrame = ctx.finalFrame(for: toView)
if isPresenting {
toView.transform = initialScale
toView.alpha = 0
toView.frame = finalFrame
container.addSubview(toView)
}
UIView.animate(withDuration: transitionDuration(using: ctx),
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.3) {
if self.isPresenting {
toView.transform = .identity
toView.alpha = 1
fromView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
fromView.alpha = 0
} else {
fromView.transform = initialScale
fromView.alpha = 0
}
} completion: { _ in
fromView.transform = .identity
ctx.completeTransition(!ctx.transitionWasCancelled)
}
}
}
// Aplicação em UINavigationControllerDelegate
extension MainViewController: UINavigationControllerDelegate {
func navigationController(
_ nc: UINavigationController,
animationControllerFor operation: UINavigationController.Operation,
from: UIViewController, to: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return ScaleTransitionAnimator(presenting: operation == .push)
}
}
Transições interativas: adicione um UIPanGestureRecognizer à tela de origem. Quando o gesto for acionado, crie um UIPercentDrivenInteractiveTransition e chame update(CGFloat(percent)). Para cancelar quando o limite não for atingido (geralmente 30%), chame cancel(). Este padrão é usado por padrão no UINavigationController para gestos de pop e no UIScrollView com pagingEnabled. Para gestos personalizados, implemente UIViewControllerInteractiveTransitioning.
Transition Framework (android.transition) é um sistema de animação declarativo que anima automaticamente as mudanças entre duas cenas (Scene). Uma cena é um conjunto de Views com um estado específico. Ao passar da Cena A para a Cena B, o Transition Framework analisa a diferença e anima: mudança de posição (ChangeBounds), mudança de tamanho (ChangeClipBounds, ChangeTransform), aparecimento (Fade) e desaparecimento (Fade).
import android.transition.Scene
import android.transition.TransitionManager
import android.transition.TransitionSet
import android.transition.AutoTransition
import android.transition.ChangeBounds
import android.transition.Fade
// TransitionSet: combinação de ChangeBounds + Fade
val transition = TransitionSet().apply {
ordering = TransitionSet.ORDERING_TOGETHER
addTransition(ChangeBounds())
addTransition(Fade(Fade.IN))
duration = 400L
interpolator = FastOutSlowInInterpolator()
}
// Transição entre cenas em um ViewGroup
val sceneRoot = findViewById<ViewGroup>(R.id.scene_root)
val scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.scene_initial)
val scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.scene_expanded)
"> AutoTransition sem configuração manual
TransitionManager.go(scene2, AutoTransition().apply {
duration = 350L
})
// TransitionManager.beginDelayedTransition — sem cenas
TransitionManager.beginDelayedTransition(sceneRoot, ChangeBounds())
itemView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
itemView.requestLayout() itemView.requestLayout() "> A alteração do layout é animada automaticamente
ChangeBounds é a transição mais usada no Android, anima mudanças de posição e tamanho da View. ChangeTransform anima rotação e escala. ChangeImageTransform — para animação de ImageView (centerCrop → fitCenter). Para transições complexas com mudanças na estrutura hierárquica, use TransitionSet com ordering = ORDERING_SEQUENTIAL (animações executam em sequência, não em paralelo). De acordo com a documentação do Android Developers (2026), o Transition Framework suporta todas as Views padrão, mas não suporta animação de superfície (SurfaceView, TextureView, VideoView).
Perguntas frequentes
Animation — anima propriedades de um único objeto (alpha, translation, scale). Transition — anima a mudança de um conjunto de objetos ou estados (fragment → fragment, scene → scene). Transition gerencia múltiplas mudanças simultaneamente: aparecimento, desaparecimento, movimento, mudança de tamanho — e anima automaticamente a diferença entre dois estados. Animation requer gerenciamento manual de cada propriedade.
Use FragmentTransaction.setCustomAnimations com Transition Framework: fragment1.exitTransition = Fade(Fade.OUT), fragment2.enterTransition = Slide(Gravity.END). Para sequenciamento: setReorderingAllowed(true) — os fragmentos serão reordenados para uma transição paralela suave. Para casos simples, slide_in_right / slide_out_left de R.anim é suficiente. Para navegação de retorno, especifique popEnter e popExit.
Transition Framework anima apenas propriedades que não acionam recálculo de layout. Para animação de altura, use ChangeBounds — ele anima automaticamente as mudanças de limites da View entre dois estados de layout. Chame TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) antes de alterar LayoutParams. Se a altura mudar via WRAP_CONTENT, certifique-se de que layout_height difere antes e depois — ChangeBounds não funcionará se ambos os estados forem match_parent.
Use o modificador .transition() com AnyTransition: .transition(.move(edge: .trailing).combined(with: .opacity)). Para transições personalizadas, implemente AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)). Para animação dentro do NavigationStack, use .navigationTransition(.slide) no iOS 18+. SwiftUI não suporta UIViewControllerAnimatedTransitioning — apenas transições declarativas via AnyTransition.
Use Profile GPU Rendering (Android) ou Core Animation Instrument (iOS). Para Android, ative o Transition Profiling via adb shell setprop debug.transition.profiling 1 — os logs mostrarão a duração de cada estágio da transição. No iOS, ative Slow Animations no simulador. Métricas alvo: duração < 400 ms, FPS >= 55, frame drops — não mais que 2 por transição. Para cenas complexas com 15+ Views animadas simultaneamente, use ChangeBounds com duração de 300 ms.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também