# Cómo mostrar spinner y barra de progreso (Progress)

> Usar Progress en los tres modos — icono girando, barra determinada e indeterminada.

Source: https://crossfly.dev/es/docs/cookbook/ui/spinner-e-progresso — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo mostrar spinner y barra de progreso (Progress)

**Propósito.** Indicar que algo está en curso. El `Progress` tiene **tres modos**,
elegidos por el constructor: icono girando (spinner), barra **determinada** (0–100% con
valor conocido) e **indeterminada** (bucle infinito, cuando no se sabe el tiempo). Usa
la determinada cuando tienes una fracción conocida (subida, descarga); la indeterminada/spinner
para "cargando..." sin fracción.

## APIs usadas
- `new Progress(Icon icon)` — **Modo spinning**: gira el icono continuamente.
- `new Progress(float min, float max)` — **Modo barra determinada**: crea la barra con el rango `[min, max]`; valor inicial = `min`.
- `progress.setValue(float v)` — actualiza el valor (limitado a `[min, max]`); recalcula la fracción rellenada. Fluido.
- `new Progress(ProgressType type)` — **Modo indeterminado**: barra/spinner infinito en el estilo dado.
- `ProgressType.MATERIAL`, `ProgressType.FLUTTER`, `ProgressType.IOS`, `ProgressType.STRIPED` — variantes visuales del modo indeterminado (`IOS` es un spinner circular; los demás son barras).
- `progress.pivot(int px, int py)` — (modo spinning) pivote de rotación personalizado; `-1,-1` = centro del icono.

> Comportamiento no obvio (confirmado en la fuente): la animación **empieza sola** cuando el
> `Progress` se añade a un padre (`onAdd`) y **se detiene** cuando se elimina (`onRemove`).
> No hay `start()`/`stop()` público — para "ocultar" el progreso, elimina el componente
> de la pantalla. El campo `mode` es final (definido en el constructor, inmutable).

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*;

/** 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());

      // 1) Spinner (icono girando) — "cargando" genérico
      Progress spinner = new Progress(new MaterialIcon("autorenew", 48));
      add(spinner);

      // 2) Barra determinada (0 a 100) — actualiza según el progreso real
      Progress barra = new Progress(0f, 100f);
      add(barra);
      // ...a medida que avanza la descarga:
      barra.setValue(75f);   // 75% relleno

      // 3) Indeterminado (loop infinito) — sin fracción conocida
      Progress infinito = new Progress(ProgressType.MATERIAL);
      add(infinito);

      // Variante spinner circular estilo iOS:
      Progress ios = new Progress(ProgressType.IOS);
      add(ios);
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo
```java
// 1) Spinner (icono girando) — "cargando" genérico
Progress spinner = new Progress(new MaterialIcon("autorenew", 48));
add(spinner);

// 2) Barra determinada (0 a 100) — actualiza según el progreso real
Progress barra = new Progress(0f, 100f);
add(barra);
// ...a medida que avanza la descarga:
barra.setValue(75f);   // 75% relleno

// 3) Indeterminado (loop infinito) — sin fracción conocida
Progress infinito = new Progress(ProgressType.MATERIAL);
add(infinito);

// Variante spinner circular estilo iOS:
Progress ios = new Progress(ProgressType.IOS);
add(ios);
```

> **Nota de verificación (código 2026).** Confirmado en la fuente: los tres constructores
> `Progress(Icon)`, `Progress(float min, float max)` y `Progress(ProgressType)`, y el
> `enum Progress.Mode { SPINNING_ICON, DETERMINATE_BAR, INDETERMINATE }` derivado de ellos.
> `setValue` limita a `[min, max]` y actualiza `progress` (fracción 0..1). El `ProgressType`
> está en `UIConstants` con los valores `IOS, FLUTTER, MATERIAL, STRIPED`. En un entorno de
> pruebas (`DeviceConfig.isTesting`) la animación no se inicia automáticamente.

## Profundiza
- Página del widget: [Progress](/docs/ui/widgets/progress) · Fuente canónica: Capítulo 14
- Feedback efímero (mensajes rápidos): [mostrar-um-hint.md](/docs/cookbook/ui/mostrar-um-hint)
