# Animaciones de valor

> AlphaAnimation, PositionAnimation y LoopAnimation — interpolar un número y aplicarlo.

Source: https://crossfly.dev/es/docs/ui/animations/value-animations — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Animaciones de valor

Los tres animadores **interpolan un número a lo largo del tiempo**. **No** dibujan nada: en el
`onUpdate` lees `getValue()` y lo aplicas donde quieras (alpha, posición, color…). Como el render es bajo
demanda, llama `Component.repaint()` en el callback.

## Comparación
| Clase | Rango | Curva | ¿Repite? | Usar para |
|---|---|---|---|---|
| `AlphaAnimation` | **[0,1]** | ease-in-out cúbico | no (tiene `onComplete`) | fade, opacidad, resalte |
| `PositionAnimation` | **libre** | lineal | no (tiene `onComplete`) | mover en píxeles, deslizar |
| `LoopAnimation` | [0,1] | lineal o eased | **sí, infinito** | pulso, glow, loading |

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.animation.*;   // AlphaAnimation, PositionAnimation, LoopAnimation
import dev.crossfly.util.*;           // Debug

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // AlphaAnimation — fade-in de una etiqueta (0→1 en 0,3s)
      Label card = new Label("Olá");
      add(LAY_AUTO, card);
      AlphaAnimation fade = new AlphaAnimation(0f, 1f, 0.3f);
      fade.onUpdate(() -> { card.alpha(fade.getValue()); Component.repaint(); })
          .onComplete(() -> Debug.log("fade concluído"))
          .start();

      // PositionAnimation — desliza un panel entrando por la derecha (en píxeles, libre)
      Label painel = new Label("Painel");
      add(LAY_AUTO, painel);
      int y0 = painel.y, w = painel.width, h = painel.height;
      PositionAnimation slide = new PositionAnimation(Screen.width, 0, 0.4f);
      slide.onUpdate(() -> { painel.setBounds((int) slide.getValue(), y0, w, h); Component.repaint(); })
           .start();

      // LoopAnimation — pulso continuo de opacidad (ciclo de 1s, suavizado, infinito)
      Label ponto = new Label("●");
      add(LAY_AUTO, ponto);
      LoopAnimation pulse = new LoopAnimation(1.0f, 60f, true);
      pulse.onUpdate(() -> { ponto.alpha(0.4f + 0.6f * pulse.getValue()); Component.repaint(); })
           .start();
   }
}
```
> Los fragmentos siguientes muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutar, colócalos en el esqueleto `MainWindow` de arriba.

## AlphaAnimation — fade-in
```java
Label card = new Label("Olá");
AlphaAnimation fade = new AlphaAnimation(0f, 1f, 0.3f);   // 0→1 en 0,3s
fade.onUpdate(() -> { card.alpha(fade.getValue()); Component.repaint(); })
    .onComplete(() -> Debug.log("fade concluído"))
    .start();
```
Constructores: `AlphaAnimation(start, end, duration)` (60 FPS) o `(start, end, duration, fps)`.

## PositionAnimation — deslizar un panel (en píxeles)
```java
int y0 = painel.y, w = painel.width, h = painel.height;
PositionAnimation slide = new PositionAnimation(Screen.width, 0, 0.4f);  // entra desde la derecha
slide.onUpdate(() -> { painel.setBounds((int) slide.getValue(), y0, w, h); Component.repaint(); })
     .start();
```
No está limitado a [0,1] y es **lineal** — ideal para coordenadas.

## LoopAnimation — pulso continuo
```java
LoopAnimation pulse = new LoopAnimation(1.0f, 60f, true);   // ciclo de 1s, 60 FPS, suavizado
pulse.onUpdate(() -> { float v = 0.4f + 0.6f * pulse.getValue(); ponto.alpha(v); Component.repaint(); })
     .start();
// pulse.stop();   // detén al salir de la pantalla
```
Constructores: `LoopAnimation(duration)` (lineal, 60 FPS) o `(duration, fps, easeInOut)`. **No** tiene
`onComplete` (corre para siempre hasta `stop()`).

## Control común
`start()` · `stop()` (dispara `onComplete` en Alpha/Position) · `cancel()` (no dispara) ·
`isRunning()` · `getValue()`.

## Buenas prácticas
- **Siempre `Component.repaint()` en el `onUpdate`** — el render es bajo demanda.
- **Detén los loops** (`stop()`) al salir de la pantalla (en `onRemove()`), si no el `Timer` sigue corriendo.
- Guarda la animación en una variable/campo para poder `stop()`/`cancel()` después.

## Errores comunes
- Usar `PositionAnimation` esperando el rango [0,1] — es libre; quien hace clamp es `AlphaAnimation`.
- Olvidar el `repaint()` y "la animación no aparece".
- Llamar `setAlpha(...)` (del Javadoc antiguo) — el método real es **`alpha(float)`**.

## Véase también
- [Transiciones de pantalla](/docs/ui/animations/screen-transitions) · [Toque y feedback](/docs/ui/animations/press-and-feedback)
