0Pricing
Android Academy · Aula

Animações de gestos e molas

Movimento natural baseado em física.

Animações de gestos e molas é uma aula grátis de Android Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Android Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Android Academy inclui 4 aulas no total.

Movimento físico e interativo

As animações mais agradáveis respondem ao dedo do usuário e dão a sensação de objetos reais, com impulso e quique. Para criá-las, você combina gestos com animações baseadas em física.

Esta lição aborda Animatable, molas, desaceleração de arremesso e sua conexão com gestos de arrastar para criar uma interface natural e interativa.

Animatable: controle de baixo nível

Enquanto animate*AsState reage ao estado, Animatable oferece controle imperativo. Você mantém uma instância em remember e a controla a partir de uma corrotina com chamadas como animateTo ou snapTo.

Essa é a base para movimentos controlados por gestos.

@Composable
fun BounceOnClick() {
    val scale = remember { Animatable(1f) }
    val scope = rememberCoroutineScope()
    Box(
        Modifier
            .graphicsLayer { scaleX = scale.value; scaleY = scale.value }
            .clickable {
                scope.launch {
                    scale.animateTo(1.3f, spring())
                    scale.animateTo(1f, spring())
                }
            }
    )
}

Molas: dampingRatio e stiffness

Uma especificação spring é definida por dois valores:

  • dampingRatio - o quanto oscila. Valores menores produzem mais oscilações; 1f (amortecimento crítico) não ultrapassa o alvo.
  • stiffness - a rapidez. Valores maiores alcançam o alvo mais rapidamente.

O Compose fornece constantes como Spring.DampingRatioMediumBouncy e Spring.StiffnessLow, portanto raramente você precisa usar números brutos.

val spec = spring<Float>(
    dampingRatio = Spring.DampingRatioLowBouncy,
    stiffness = Spring.StiffnessMedium
)

// later, inside a coroutine:
// offset.animateTo(targetValue = 0f, animationSpec = spec)

Detectando gestos de arrastar

Para tornar o movimento interativo, leia a entrada de toque. Modifier.pointerInput com detectDragGestures informa os deslocamentos do arrasto enquanto o usuário move o dedo.

Você acumula esses deslocamentos em um deslocamento e o aplica ao componente.

@Composable
fun Draggable() {
    var offsetX by remember { mutableStateOf(0f) }
    Box(
        Modifier
            .offset { IntOffset(offsetX.roundToInt(), 0) }
            .size(80.dp)
            .background(Color.Red)
            .pointerInput(Unit) {
                detectDragGestures { change, drag ->
                    change.consume()
                    offsetX += drag.x
                }
            }
    )
}

Voltando com uma mola

Combine o arrasto com Animatable para obter um efeito de "voltar ao lugar". Enquanto arrasta, use snapTo para posicionar o elemento instantaneamente sob o dedo; ao soltá-lo, use animateTo(0f) com uma mola para que ele salte de volta à posição inicial.

@Composable
fun SnapBack() {
    val offsetX = remember { Animatable(0f) }
    val scope = rememberCoroutineScope()
    Box(
        Modifier
            .offset { IntOffset(offsetX.value.roundToInt(), 0) }
            .size(80.dp)
            .background(Color.Blue)
            .pointerInput(Unit) {
                detectDragGestures(
                    onDrag = { change, drag ->
                        change.consume()
                        scope.launch { offsetX.snapTo(offsetX.value + drag.x) }
                    },
                    onDragEnd = {
                        scope.launch { offsetX.animateTo(0f, spring()) }
                    }
                )
            }
    )
}

Arremesso com velocidade

Arremessos reais continuam em movimento depois que o dedo é levantado. Acompanhe a velocidade com um VelocityTracker e depois passe-a para animateDecay, para que o elemento desacelere naturalmente usando um DecayAnimationSpec baseado em atrito.

val decay = rememberSplineBasedDecay<Float>()

// on drag end, with measured velocity:
// scope.launch {
//     offsetX.animateDecay(
//         initialVelocity = velocity,
//         animationSpec = decay
//     )
// }

Deslizar para dispensar com âncoras

Para gestos de deslizar com posições de repouso fixas, como deslizar para dispensar, anchoredDraggable ajusta o elemento às âncoras definidas. Você declara os estados e suas posições em pixels, e o Compose cuida da mola entre eles.

enum class DragValue { Start, End }

val state = remember {
    AnchoredDraggableState(
        initialValue = DragValue.Start,
        anchors = DraggableAnchors {
            DragValue.Start at 0f
            DragValue.End at 300f
        }
    )
}

Animações infinitas e repetidas

Para movimentos contínuos, como um ponto pulsante ou um efeito de carregamento, use rememberInfiniteTransition com infiniteRepeatable. Defina RepeatMode como Reverse para fazer um movimento de vai e volta, ou como Restart para repetir desde o início.

@Composable
fun Pulse() {
    val transition = rememberInfiniteTransition(label = "pulse")
    val scale by transition.animateFloat(
        initialValue = 1f,
        targetValue = 1.2f,
        animationSpec = infiniteRepeatable(
            animation = tween(700),
            repeatMode = RepeatMode.Reverse
        ),
        label = "scale"
    )
    Box(Modifier.graphicsLayer { scaleX = scale; scaleY = scale })
}

Combinando gesto e mola

O padrão interativo clássico: arrastar para mover e soltar para acomodar. Acompanhe a velocidade durante o arrasto e depois faça um arremesso com animateDecay ou acomode o elemento em direção a uma âncora com uma spring, dependendo da distância ou da velocidade.

É exatamente assim que painéis inferiores, carrosséis e cartões dispensáveis proporcionam uma sensação tão natural.

// pattern:
// 1) onDrag    -> animatable.snapTo(current + delta)
// 2) onDragEnd -> if (fast) animatable.animateDecay(velocity, decay)
//                 else      animatable.animateTo(nearestAnchor, spring())

Acomodação com mola em Kotlin puro

Para entender como uma mola se acomoda, veja este loop mínimo escrito apenas em Kotlin. Ele aplica uma força restauradora em direção ao alvo e reduz a velocidade a cada etapa — a mesma ideia que o Compose executa a cada quadro.

fun main() {
    var pos = 0f
    var vel = 0f
    val target = 200f
    val stiffness = 0.2f
    val damping = 0.75f
    repeat(8) { step ->
        vel = (vel + (target - pos) * stiffness) * damping
        pos += vel
        println("step $step pos=${"%.1f".format(pos)}")
    }
}

Toques, pressionamentos e vários gestos

Arrastar não é o único gesto. pointerInput também oferece detectTapGestures para toques, toques duplos e pressionamentos longos, além de detectTransformGestures para zoom com pinça e rotação.

Aqui, um pressionamento longo ativa uma escala com mola, combinando a detecção de gestos com um Animatable.

@Composable
fun LongPressScale() {
    val scale = remember { Animatable(1f) }
    val scope = rememberCoroutineScope()
    Box(
        Modifier
            .graphicsLayer { scaleX = scale.value; scaleY = scale.value }
            .pointerInput(Unit) {
                detectTapGestures(
                    onLongPress = {
                        scope.launch { scale.animateTo(1.4f, spring()) }
                    },
                    onPress = {
                        tryAwaitRelease()
                        scope.launch { scale.animateTo(1f, spring()) }
                    }
                )
            }
    )
}

Verificação rápida

Você está criando um cartão arrastável que deve voltar à origem com um salto quando for solto. Qual combinação é a escolha idiomática no Compose?

Recapitulação: gestos e molas

Agora você consegue criar movimentos naturais e interativos:

  • Animatable oferece controle imperativo orientado por corrotinas por meio de animateTo / snapTo.
  • spring é ajustada com dampingRatio (salto) e stiffness (velocidade).
  • pointerInput + detectDragGestures transformam o toque em movimento; animateDecay adiciona o arremesso.
  • anchoredDraggable ajusta o elemento a posições fixas em interações de deslizar.
  • rememberInfiniteTransition conduz efeitos em loop, como pulsações e brilhos de carregamento.

Isso conclui o conteúdo sobre animações no Jetpack Compose. Agora você pode animar valores, visibilidade, conteúdo e gestos com confiança.

Perguntas Frequentes

A aula “Animações de gestos e molas” é grátis?

Sim — o texto completo de “Animações de gestos e molas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Android Academy, atualize para CoddyKit PRO. O curso de Android Academy inclui 4 aulas no total.

O que vou aprender em “Animações de gestos e molas”?

Movimento natural baseado em física. Você pratica Android Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Android Academy?

Nenhuma experiência prévia é necessária. Android Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Animações de gestos e molas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Android Academy?

Sim. Cada aula de Android Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que as animações são importantes
  2. Noções básicas de animate*AsState
  3. AnimatedVisibility e transições
  4. Animações de gestos e molas
← Voltar para Android Academy