O movimento baseado em física é realizado por força. A força elástica é uma das forças que guia a interatividade e o movimento. Ela tem as seguintes propriedades: amortecimento e rigidez. Em uma animação baseada em objetos elásticos, o valor e a velocidade são calculados pela força elástica aplicada em cada frame.
Se você quiser que as animações do seu app desacelerem em apenas uma direção, use uma animação de rolagem com desaceleração baseada em atrito.
Ciclo de vida de uma animação de mola
Em uma animação baseada em objetos elásticos, a classe SpringForce
permite personalizar a rigidez da mola, a proporção de amortecimento e a posição final. Assim que a animação começa, a força elástica atualiza o valor e a velocidade da animação em cada frame. A animação continua até que a força elástica atinja um equilíbrio.
Por exemplo, se você arrastar um ícone do app pela tela e depois soltá-lo levantando seu dedo, o ícone voltará ao local original por uma força invisível, mas conhecida.
A Figura 1 demonstra um efeito de mola semelhante. O sinal de adição (+) no meio do círculo indica a força aplicada por meio de um gesto de toque.

Criar uma animação de mola
As etapas gerais para criar uma animação de mola para seu aplicativo são as seguintes:
- Adicionar a Biblioteca de Suporte: é preciso adicionar a Biblioteca de Suporte ao projeto para usar as classes de animação de mola.
- Criar uma animação de mola:
a principal etapa é criar uma instância da classe
SpringAnimation
e definir os parâmetros de comportamento do movimento. - Registrar listeners (opcional):
registre listeners para observar mudanças no ciclo de vida e atualizações no valor da animação.
Observação: registre o listener de atualização somente se você precisar de atualizações por frame sobre as mudanças de valor da animação. Um listener de atualização evita que a animação seja executada em uma linha de execução diferente.
- Remover listeners (opcional): remova os listeners que não estiverem mais sendo usados.
- Definir um valor inicial (opcional): personalize o valor inicial da animação.
- Definir um intervalo de valores (opcional): defina um intervalo de valores de animação para restringi-los aos limites mínimo e máximo.
- Definir uma velocidade inicial (opcional): defina a velocidade inicial da animação.
- Definir propriedades da mola (opcional): defina a proporção de amortecimento e a rigidez na mola.
- Criar uma mola personalizada (opcional): crie uma mola personalizada caso você não pretenda usar a mola padrão ou queira usar a mesma mola em toda a animação.
- Iniciar a animação: inicie a animação de mola.
- Cancelar animação (opcional): cancele a animação caso o usuário saia repentinamente do app ou a visualização se torne invisível.
As seções a seguir discutem em detalhes as etapas gerais de como criar uma animação de mola.
Adicionar a Biblioteca de Suporte
Para usar a Biblioteca de Suporte baseada em física, é preciso adicioná-la ao seu projeto da seguinte forma:
- Abra o arquivo
build.gradle
para o módulo do seu app. Adicione a Biblioteca de Suporte à seção
dependencies
.dependencies { def dynamicanimation_version = "1.0.0" implementation 'androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version' }
Para ver as versões atuais dessa biblioteca, consulte as informações sobre Dynamicanimation na página de versões.
Criar uma animação de mola
A classe SpringAnimation
permite criar uma animação de mola para um objeto. Para criar uma animação de mola, é necessário criar uma instância da classe SpringAnimation
e fornecer um objeto, uma propriedade do objeto que você quer animar e uma posição final opcional da mola onde quer que a animação permaneça.
Observação: no momento da criação de uma animação de mola, a posição final é opcional. No entanto, isso precisa ser definido antes do início da animação.
Kotlin
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
A animação baseada em mola pode animar visualizações na tela mudando as propriedades reais nos objetos de visualização. As visualizações a seguir estão disponíveis no sistema:
ALPHA
: representa a transparência Alfa na visualização. O valor é 1 (opaco) por padrão, sendo que o valor 0 representa transparência total (não visível).TRANSLATION_X
,TRANSLATION_Y
eTRANSLATION_Z
: essas propriedades controlam onde a visualização está localizada como um delta a partir da coordenada esquerda, da coordenada superior e da elevação, que são definidas pelo contêiner de layout.TRANSLATION_X
descreve a coordenada esquerda.TRANSLATION_Y
descreve a coordenada superior.TRANSLATION_Z
descreve a profundidade da visualização em relação à elevação.
ROTATION
,ROTATION_X
eROTATION_Y
: essas propriedades controlam a rotação em 2D (propriedaderotation
) e em 3D ao redor do ponto de rotação.SCROLL_X
eSCROLL_Y
: essas propriedades indicam o deslocamento de rolagem da origem esquerda e da borda superior em pixels. Elas também indicam a posição com relação ao quanto a página é rolada.SCALE_X
eSCALE_Y
: essas propriedades controlam o escalonamento 2D de uma visualização ao redor do ponto de rotação.X
,Y
eZ
: são propriedades utilitárias básicas para descrever o local final da visualização no contêiner.X
é uma soma do valor da esquerda eTRANSLATION_X
.Y
é uma soma do valor superior eTRANSLATION_Y
.Z
é uma soma do valor de elevação eTRANSLATION_Z
.
Registrar listeners
A classe DynamicAnimation
oferece dois listeners: OnAnimationUpdateListener
e OnAnimationEndListener
.
Esses listeners ouvem as atualizações na animação, como quando há uma mudança no valor da animação e quando a animação termina.
OnAnimationUpdateListener
Quando você quiser animar várias visualizações para criar uma animação encadeada, configure OnAnimationUpdateListener
para receber um callback sempre que houver mudanças na propriedade da visualização atual. O callback notifica a outra visualização para atualizar a posição da mola com base na mudança feita na propriedade da visualização atual. Para registrar o listener, siga estas etapas:
-
Chame o método
addUpdateListener()
e anexe o listener à animação.Observação: é necessário registrar o listener de atualização antes que a animação comece. No entanto, registre o listener de atualização somente se você precisar de atualizações por frame sobre as mudanças de valor da animação. Um listener de atualização evita que a animação seja executada em uma linha de execução diferente.
-
Modifique o método
onAnimationUpdate()
para notificar o autor da chamada sobre a mudança no objeto atual. A amostra de código a seguir ilustra o uso geral deOnAnimationUpdateListener
.
Kotlin
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
OnAnimationEndListener
OnAnimationEndListener
notifica o final de uma animação. É possível configurar o listener para receber callbacks sempre que a animação atingir o equilíbrio ou for cancelada. Para registrar o listener, siga estas etapas:
-
Chame o método
addEndListener()
e anexe o listener à animação. -
Modifique o método
onAnimationEnd()
para receber uma notificação sempre que uma animação atingir o equilíbrio ou for cancelada.
Remover listeners
Para não receber mais callbacks de atualizações e de fim de animação, chame os métodos removeUpdateListener()
e removeEndListener()
, respectivamente.
Definir o valor inicial da animação
Para definir o valor inicial da animação, chame o método setStartValue()
e transmita o valor inicial da animação. Se o valor inicial não for definido, a animação usará o valor atual da propriedade do objeto.
Definir intervalo de valores de animação
É possível definir os valores mínimo e máximo da animação para restringir o valor da propriedade a um determinado intervalo. Isso também ajudará a controlar o intervalo se você estiver animando propriedades que têm um intervalo intrínseco, como Alfa (de 0 a 1).
-
Para definir o valor mínimo, chame o método
setMinValue()
e transmita o valor mínimo da propriedade. -
Para definir o valor máximo, chame o método
setMaxValue()
e transmita o valor máximo da propriedade.
Ambos os métodos retornam a animação para a qual o valor está sendo definido.
Observação: se você definiu o valor inicial e um intervalo de valores de animação, verifique se o valor inicial está dentro dos limites mínimo e máximo.
Definir a velocidade inicial
A velocidade inicial define a velocidade em que a propriedade muda no início da animação. O padrão dela é zero pixel por segundo, mas ela pode ser definida com a velocidade dos gestos de toque ou um valor fixo escolhido. Se você optar por informar um valor fixo, recomendamos definir o valor em dp por segundo e depois convertê-lo em pixels por segundo. A definição do valor em dp por segundo permite que a velocidade seja independente da densidade e dos formatos. Para mais informações sobre como converter o valor para pixels por segundo, consulte a seção Converter dp por segundo em pixels por segundo.
Para definir a velocidade, chame o método setStartVelocity()
e transmita a velocidade em pixels por segundo. O método retorna o objeto de força elástica em que a velocidade está definida.
Observação: use os métodos de classe GestureDetector.OnGestureListener
ou VelocityTracker
para recuperar e calcular a velocidade dos gestos de toque.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
Converter dp por segundo em pixels por segundo
A velocidade de uma mola precisa ser definida em pixels por segundo. Se você optar por informar um valor fixo como o início da velocidade, defina o valor em dp por segundo e depois converta-o em pixels por segundo. Para a conversão, use o método applyDimension()
da classe TypedValue
. Consulte a seguinte amostra de código:
Kotlin
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
Definir propriedades da mola
A classe SpringForce
define os métodos getter e setter para cada propriedade da mola, como a proporção de amortecimento e a rigidez. Para definir as propriedades da mola, é importante recuperar o objeto de força elástica ou criar uma força elástica personalizada em que você possa definir as propriedades. Para mais informações sobre como criar uma força elástica personalizada, consulte a seção Criar uma força elástica personalizada.
Dica: ao usar os métodos setter, você pode criar uma cadeia de métodos, já que todos os métodos setter retornam o objeto de força elástica.
Proporção de amortecimento
A proporção de amortecimento descreve uma redução gradual na oscilação da mola. Ao usar a taxa de amortecimento, é possível definir a rapidez com que as oscilações diminuem de uma oscilação para a próxima. Há quatro maneiras diferentes de amortecer uma mola:
- O amortecimento excessivo ocorre quando a proporção é maior que um. Ele permite que o objeto retorne rapidamente à posição de repouso.
- O amortecimento crítico ocorre quando a proporção é igual a um. Ele permite que o objeto retorne à posição de repouso no menor tempo possível.
- O amortecimento insuficiente ocorre quando a proporção é inferior a um. Ele permite que o objeto ultrapasse várias vezes a posição de repouso, atingindo-a gradativamente em seguida.
- O não amortecimento ocorre quando a proporção é igual a zero. Ele permite que o objeto oscile para sempre.
Para adicionar a proporção de amortecimento à mola, siga estas etapas:
-
Chame o método
getSpring()
para recuperar a mola e adicionar a proporção de amortecimento. -
Chame o método
setDampingRatio()
e transmita a proporção de amortecimento que você quer adicionar à mola. O método retorna o objeto de força elástica em que a proporção de amortecimento é definida.Observação: a proporção de amortecimento precisa ser um número não negativo. Se você definir a proporção de amortecimento como zero, a mola nunca atingirá a posição de repouso. Em outras palavras, ele oscilará para sempre.
As seguintes constantes de proporção de amortecimento estão disponíveis no sistema:
DAMPING_RATIO_HIGH_BOUNCY
DAMPING_RATIO_MEDIUM_BOUNCY
DAMPING_RATIO_LOW_BOUNCY
DAMPING_RATIO_NO_BOUNCY
Figura 2: oscilação alta
Figura 3: oscilação média
Figura 4: oscilação baixa
Figura 5: sem oscilação
A proporção de amortecimento padrão é definida como DAMPING_RATIO_MEDIUM_BOUNCY
.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
Rigidez
A rigidez define a constante da mola, que mede a intensidade. Uma mola rígida aplica mais força ao objeto fixado quando não está na posição de repouso. Para adicionar rigidez à mola, siga estas etapas:
-
Chame o método
getSpring()
para recuperar a mola e adicionar rigidez. -
Chame o método
setStiffness()
e transmita o valor de rigidez que você quer adicionar à mola. O método retorna o objeto de força elástica em que a rigidez está definida.Observação: a rigidez precisa ser um número positivo.
As seguintes constantes de rigidez estão disponíveis no sistema:
Figura 6: rigidez alta
Figura 7: rigidez média
Figura 8: rigidez baixa
Figura 9: rigidez muito baixa
A rigidez padrão é definida como STIFFNESS_MEDIUM
.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
Criar uma força elástica personalizada
Você pode criar uma força elástica personalizada como alternativa ao uso da força elástica padrão. A força elástica personalizada permite compartilhar a mesma instância de força elástica em várias animações. Depois de criar a força elástica, é possível definir propriedades como a proporção de amortecimento e a rigidez.
-
Crie um objeto
SpringForce
.SpringForce force = new SpringForce();
-
Atribua as propriedades chamando os respectivos métodos. Você também pode criar uma cadeia de métodos.
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);
-
Chame o método
setSpring()
para definir a mola da animação.setSpring(force);
Iniciar animação
Há duas maneiras de iniciar uma animação de mola: chamando o método start()
ou o animateToFinalPosition()
. Os dois métodos precisam ser chamados na linha de execução principal.
O método animateToFinalPosition()
é responsável por estas duas tarefas:
- Definir a posição final da mola.
- Iniciar a animação, se ela não tiver sido iniciada.
Como o método atualiza a posição final da mola e inicia a animação se necessário, você pode chamar esse método a qualquer momento para mudar o curso de uma animação. Por exemplo, em uma animação de mola encadeada, a animação de uma visualização depende de outra visualização. Para esse tipo de animação, é mais conveniente usar o método animateToFinalPosition()
. Ao usar esse método em uma animação de mola encadeada, você não precisa se preocupar se a animação que quer atualizar em seguida está ou não em execução no momento.
A Figura 10 ilustra uma animação de mola encadeada, em que a animação de uma visualização depende de outra.

Para usar o método animateToFinalPosition()
, chame o método animateToFinalPosition()
e transmita a posição de repouso da mola. Você também pode definir a posição de repouso da mola chamando o método setFinalPosition()
.
O método start()
não define o valor da propriedade para o valor inicial de imediato. O valor da propriedade muda a cada pulso da animação, o que acontece antes da passagem do desenho.
Como resultado, as mudanças são refletidas no frame seguinte, como se os valores fossem definidos imediatamente.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … //Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … //Starting the animation anim.start(); …
Cancelar animação
Você pode cancelar ou pular para o final da animação. A situação ideal em que é necessário cancelar ou pular para o final da animação é quando uma interação do usuário exige que a animação seja encerrada imediatamente. Isso ocorre principalmente quando o usuário sai de um app de maneira repentina ou quando a visualização se torna invisível.
Há dois métodos que você pode usar para encerrar a animação.
O método cancel()
encerra a animação no valor em que está. O método skipToEnd()
pula a animação para o valor final e depois a encerra.
Antes de encerrar a animação, é importante verificar primeiro o estado da mola. Se o estado não for amortecido, a animação nunca atingirá a posição de repouso.
Para verificar o estado da mola, chame o método canSkipToEnd()
. Se a mola estiver amortecida, o método retornará true
. Caso contrário, ele retornará false
.
Depois de saber o estado da mola, você pode encerrar uma animação usando o método skipToEnd()
ou o cancel()
. O método cancel()
precisa ser chamado apenas na linha de execução principal.
Observação: em geral, o método skipToEnd()
causa um salto visual.