Pontos-chave
Easing (função de suavização) é uma função matemática f(t) que mapeia o tempo linear t ∈ [0,1] para um valor de animação não linear. Se uma animação muda a posição de um objeto de A para B em 500 ms, o easing determina como o objeto se move entre esses pontos em cada momento. O easing linear (f(t) = t) significa velocidade constante — o objeto se move mecanicamente. O easing não linear parece natural: o objeto acelera (ease-in), desacelera (ease-out) ou tem um início e fim suaves (ease-in-out).
As funções de easing são descritas por curvas Bézier cúbicas, onde o eixo X é o tempo normalizado e o eixo Y é o progresso normalizado. Dois pontos de controle (P1, P2) definem a forma da curva. As curvas padrão são fixadas pela especificação CSS: ease (0.25, 0.1, 0.25, 1.0), ease-in (0.42, 0.0, 1.0, 1.0), ease-out (0.0, 0.0, 0.58, 1.0), ease-in-out (0.42, 0.0, 0.58, 1.0). Esses mesmos valores são usados no CAMediaTimingFunction no iOS e no PathInterpolator no Android. De acordo com as Diretrizes de Movimento do Material Design, as curvas de easing devem corresponder ao contexto: para aparecimento — ease-out (início rápido), para desaparecimento — ease-in (final rápido).
No iOS, o easing funciona principalmente através da classe CAMediaTimingFunction do Core Animation. Ela aceita uma curva Bézier cúbica como dois pontos de controle (c1x, c1y, c2x, c2y) e se aplica a CAAnimation (CABasicAnimation, CAKeyframeAnimation). CAMediaTimingFunction suporta 5 funções predefinidas: linear, easeIn, easeOut, easeInEaseOut e default (equivalente a easeInEaseOut).
CAMediaTimingFunction funciona no nível CALayer — a animação é executada em um processo separado do servidor de renderização, garantindo 60fps mesmo com transformações complexas. Para animação de propriedades UIView (frame, alpha, transform), o UIKit usa UIView.animate com o parâmetro options: .curveEaseInOut, que internamente também cria uma CAMediaTimingFunction com a curva correspondente. No iOS 17+, foi adicionado UIViewAnimationCurve.custom com BlockParameters para Bézier personalizada — isso elimina a necessidade de escrever CAAnimation personalizada. CAMediaTimingFunction também é usado no UIKit Dynamics e UIScrollView para desaceleração (UIScrollViewDecelerationRate).
No SwiftUI, o easing é definido através da estrutura Animation com os modificadores .easeIn, .easeOut, .easeInOut, .spring e .interpolatingSpring. Ao contrário do UIKit, onde a animação é procedural (beginAnimations/commitAnimations), o SwiftUI usa uma abordagem declarativa: a animação é uma propriedade de estado que muda, e o framework determina como animar a transição.
O modificador .timingCurve(c0x, c0y, c1x, c1y) aceita pontos de controle Bézier cúbica diretamente — é um análogo completo do CAMediaTimingFunction. O SwiftUI Animation suporta curvas predefinidas como propriedades estáticas: Animation.easeInOut é equivalente a ease-in-out (0.42, 0.0, 0.58, 1.0). Para animação spring, usa-se Animation.spring(response:dampingFraction:blendDuration), onde dampingFraction < 1 cria um efeito de mola com amortecimento. Na WWDC 2023, a Apple apresentou Animation.keyframes — animação quadro a quadro com easing personalizado em cada quadro-chave, dando controle total sobre a trajetória.
No Android, o easing é implementado através de PathInterpolator (API 21+) — uma classe que aceita um objeto Path com uma curva Bézier cúbica. Os pontos de controle são especificados via Path.cubicTo(x1, y1, x2, y2, x3, y3), onde (x1,y1) é o primeiro ponto de controle, (x2,y2) é o segundo, e (x3,y3) é o ponto final (sempre 1,1). PathInterpolator é obrigatório se uma curva personalizada for necessária; para cenários padrão, AccelerateDecelerateInterpolator (ease-in-out), AccelerateInterpolator (ease-in) e DecelerateInterpolator (ease-out) estão disponíveis.
No Jetpack Compose, o easing é definido através do objeto Easing do pacote androidx.compose.animation. FastOutSlowInEasing, LinearOutSlowInEasing, FastOutLinearInEasing estão disponíveis, bem como Easing personalizado através de CubicBezierEasing. O Compose Easing é aplicado em animate*AsState, AnimatedVisibility e AnimatedContent. A diferença principal do sistema View: o Compose interpola o easing no lado Kotlin (não no RenderNode), o que dá mais flexibilidade para animações personalizadas, mas requer otimização em displays de 120Hz.
Animação básica de posição de camada com uma curva ease-in-out personalizada. CAMediaTimingFunction aceita pontos de controle Bézier cúbica que definem um início e fim suaves do movimento.
import UIKit
func animateLayerPosition() {
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = CGPoint(x: 0, y: 0)
animation.toValue = CGPoint(x: 300, y: 400)
animation.duration = 0.8
let easing = CAMediaTimingFunction(
controlPoints: 0.42, 0.0, 0.58, 1.0
)
animation.timingFunction = easing
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
layer.add(animation, forKey: "positionAnimation")
}
Os pontos de controle (0.42, 0.0, 0.58, 1.0) definem a curva padrão ease-in-out. O SwiftUI usa os mesmos pontos para Animation.easeInOut. Para ease-in, use (0.42, 0.0, 1.0, 1.0); para ease-out — (0.0, 0.0, 0.58, 1.0). O Core Animation executa a animação no servidor de renderização a 60/120 fps.
Animação declarativa no SwiftUI com uma curva personalizada e efeito spring. O modificador animation vincula-se à mudança de isAnimated.
import SwiftUI
struct EasingExampleView: View {
@State private var isAnimated = false
var body: some View {
VStack {
Circle()
.fill(Color.blue)
.frame(width: 60, height: 60)
.offset(x: isAnimated ? 100 : 0, y: 0)
.animation(
.timingCurve(0.42, 0.0, 0.58, 1.0, duration: 0.6),
value: isAnimated
)
Button("Toggle") {
isAnimated.toggle()
}
}
}
}
O modificador .timingCurve(c0x, c0y, c1x, c1y, duration) cria uma animação de easing personalizada no SwiftUI. O parâmetro value vincula a animação a um estado específico — quando isAnimated muda, o SwiftUI aplica automaticamente a curva. Para animação spring, use .spring(response: 0.4, dampingFraction: 0.6) em vez de timingCurve.
O equivalente de ease-in-out no Android através de PathInterpolator. Os pontos de controle (0.42, 0.0, 0.58, 1.0) definem a mesma curva que no iOS.
import android.animation.ObjectAnimator
import android.graphics.Path
import android.view.animation.PathInterpolator
import android.view.View
fun View.fadeInWithEase() {
val path = Path().apply {
cubicTo(0.42f, 0.0f, 0.58f, 1.0f, 1.0f, 1.0f)
}
val interpolator = PathInterpolator(path)
ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).apply {
duration = 500
interpolator = interpolator
start()
}
}
PathInterpolator com pontos de controle (0.42, 0.0, 0.58, 1.0) é idêntico ao CAMediaTimingFunction ease-in-out no iOS. Para projetos multiplataforma, use os mesmos pontos de controle — isso garante um comportamento de animação visualmente idêntico. O Material Design recomenda FastOutSlowInInterpolator (0.4, 0.0, 0.2, 1.0) como alternativa para interfaces específicas do Android.
No Compose, o easing é definido através de CubicBezierEasing com os mesmos pontos de controle. O resultado é um aparecimento suave do elemento com transparência e deslocamento.
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
@Composable
fun EasingComposable() {
var visible by remember { mutableStateOf(false) }
val easing = CubicBezierEasing(0.42f, 0.0f, 0.58f, 1.0f)
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
animationSpec = tween(durationMillis = 500, easing = easing)
)
Column {
Button(onClick = { visible = !visible }) {
Text("Toggle")
}
Box(
modifier = Modifier
.size(100.dp)
.graphicsLayer(alpha = alpha)
.background(MaterialTheme.colorScheme.primary)
)
}
}
CubicBezierEasing no Compose aceita os mesmos 4 parâmetros de pontos de controle. O animateFloatAsState interpola automaticamente o valor alpha com a curva especificada. Para comparação: FastOutSlowInEasing no Compose é equivalente a (0.4, 0.0, 0.2, 1.0) — a curva padrão do Material Design 3. Curvas personalizadas via CubicBezierEasing dão controle total para animações de marca.
Perguntas Frequentes
Easing é um conceito geral de função de suavização usado no iOS (CAMediaTimingFunction), na web (CSS ease-in-out) e no design. Interpolator é a implementação deste conceito no Android (TimeInterpolator). Essencialmente são a mesma coisa — uma curva matemática de velocidade de animação. A diferença é apenas no nome e na API da plataforma. Em projetos multiplataforma, o termo easing é usado como universal.
O iOS fornece CAMediaTimingFunction com 5 funções predefinidas: linear, easeIn, easeOut, easeInEaseOut e custom (Bézier cúbica). No SwiftUI, estão disponíveis Animation.easeIn, Animation.easeOut, Animation.easeInOut, Animation.spring e Animation.interpolatingSpring. Para curvas personalizadas, use Animation.timingCurve(c0x, c0y, c1x, c1y, duration:).
Sim, se a mesma curva Bézier cúbica for configurada. CAMediaTimingFunction no iOS e PathInterpolator no Android aceitam pontos de controle Bézier cúbica (x1, y1, x2, y2). Por exemplo, a curva ease-in-out (0.42, 0.0, 0.58, 1.0) dará comportamento idêntico em ambas as plataformas. O Material Design usa esta abordagem para animações multiplataforma.
Use as Diretrizes de Movimento do Material Design: para aparecimento de elementos — ease-out (início rápido, final suave), para desaparecimento — ease-in (final rápido), para movimento entre telas — ease-in-out. Use animação spring para elementos interativos (botões, cartões). Evite linear — parece antinatural.
A trepidação (jank) ocorre quando a animação não atinge 60fps. Verifique: você está usando CAMediaTimingFunction (não um timer) no iOS, PathInterpolator (não Handler.post) no Android. Cálculos pesados na thread principal, hierarquia de camadas complexa ou um drawable grande podem causar queda de quadros. No iOS, use Core Animation com shouldRasterize para camadas complexas; no Android — Hardware Acceleration e renderização GPU.
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