# 如何显示加载指示器和进度条（Progress）

> 以三种模式使用 Progress —— 旋转图标、确定进度条和不确定进度条。

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

# 如何显示加载指示器和进度条（Progress）

**目的。** 表明某项操作正在进行中。`Progress` 有**三种模式**，
由构造函数选择：旋转图标（加载指示器）、**确定**进度条（0–100%，值已知）和
**不确定**进度条（无限循环，当时长未知时）。当你有已知比例时使用确定模式
（上传、下载）；对于没有比例的「加载中……」使用不确定模式/加载指示器。

## 所用 API
- `new Progress(Icon icon)` — **旋转模式**：持续旋转图标。
- `new Progress(float min, float max)` — **确定进度条模式**：以区间 `[min, max]` 创建进度条；初始值 = `min`。
- `progress.setValue(float v)` — 更新值（钳制到 `[min, max]`）；重新计算已填充比例。流式。
- `new Progress(ProgressType type)` — **不确定模式**：给定样式的无限进度条/加载指示器。
- `ProgressType.MATERIAL`、`ProgressType.FLUTTER`、`ProgressType.IOS`、`ProgressType.STRIPED` — 不确定模式的视觉变体（`IOS` 是圆形加载指示器；其余为进度条）。
- `progress.pivot(int px, int py)` —（旋转模式）自定义旋转轴心；`-1,-1` = 图标中心。

> 不易察觉的行为（已在源码中确认）：当 `Progress` 被添加到父级时（`onAdd`），
> 动画会**自行开始**，并在被移除时（`onRemove`）**停止**。
> 没有公开的 `start()`/`stop()` —— 要「隐藏」进度，请把组件
> 从屏幕上移除。`mode` 字段为 final（在构造函数中定义，不可变）。

## 完整示例（复制、粘贴即可运行）
```java
package com.exemplo;

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

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // 1) Spinner（旋转图标）— 通用的"加载中"
      Progress spinner = new Progress(new MaterialIcon("autorenew", 48));
      add(spinner);

      // 2) 确定进度条（0 到 100）— 按真实进度更新
      Progress barra = new Progress(0f, 100f);
      add(barra);
      // ... 随着下载推进：
      barra.setValue(75f);   // 已填充 75%

      // 3) 不确定进度（无限循环）— 无已知比例
      Progress infinito = new Progress(ProgressType.MATERIAL);
      add(infinito);

      // iOS 风格的圆形 spinner 变体：
      Progress ios = new Progress(ProgressType.IOS);
      add(ios);
   }
}
```

> 下面的片段只展示**核心部分**。要运行它，请把它放进上面的 `MainWindow` 骨架中。

## 最小片段
```java
// 1) Spinner（旋转图标）— 通用的"加载中"
Progress spinner = new Progress(new MaterialIcon("autorenew", 48));
add(spinner);

// 2) 确定进度条（0 到 100）— 按真实进度更新
Progress barra = new Progress(0f, 100f);
add(barra);
// ... 随着下载推进：
barra.setValue(75f);   // 已填充 75%

// 3) 不确定进度（无限循环）— 无已知比例
Progress infinito = new Progress(ProgressType.MATERIAL);
add(infinito);

// iOS 风格的圆形 spinner 变体：
Progress ios = new Progress(ProgressType.IOS);
add(ios);
```

> **验证说明（2026 代码）。** 已在源码中确认：三个构造函数
> `Progress(Icon)`、`Progress(float min, float max)` 和 `Progress(ProgressType)`，以及
> 由它们派生的 `enum Progress.Mode { SPINNING_ICON, DETERMINATE_BAR, INDETERMINATE }`。
> `setValue` 钳制到 `[min, max]` 并更新 `progress`（比例 0..1）。`ProgressType`
> 位于 `UIConstants`，取值为 `IOS, FLUTTER, MATERIAL, STRIPED`。在测试环境中
> （`DeviceConfig.isTesting`），动画不会自动开始。

## 深入了解
- 控件页面：[Progress](/docs/ui/widgets/progress) · 权威来源：第 14 章
- 短暂反馈（快速消息）：[mostrar-um-hint.md](/docs/cookbook/ui/mostrar-um-hint)
