# ImageView

> 显示 Image，可配置缩放模式（ImageSize）和对齐方式。

Source: https://crossfly.dev/zh/docs/ui/widgets/imageview — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# ImageView

`ImageView` 在组件边界内渲染一个 [`Image`](/docs/ui/images-and-graphics)，缩放模式由枚举 [`ImageSize`](/docs/reference) 控制，水平/垂直对齐通过 `Position` 设置。它是在布局中显示固定图像（照片、封面、logo）的声明式方式。

在内部，它维护一份**缩放后的缓存副本**（`ResizeMode.STRETCH`、`ResizeQuality.FAST`），以避免每一帧都重新调整大小；当更换图像、缩放模式或尺寸时，缓存会失效。

> 🟢 · **包：** `dev.crossfly.ui` · **继承：** `Component` · **样式：** `ComponentStyle`（使用 `ingap` 作为内部 margin）

## 何时使用
- 在布局中显示固定图像：照片、封面、logo、头像。
- 调整图像如何填充空间（宽高比、覆盖、拉伸）。

## 何时不要使用
- 逐帧动画、连续可变缩放或复合绘制 → 编写你自己的 `Component`，在 `onPaint` 中直接调用 `paint.image(...)`（见 [`images-and-graphics/`](/docs/ui/images-and-graphics)）。
- 另一个组件的**背景**图像 → 使用 `Component` 自身的 `BackgroundImage`（第 18 章）。

## 外观
图像默认在内部区域内（应用 `ingap` 之后）居中，并根据 `ImageSize` 缩放：

| `ImageSize` | 行为 |
|---|---|
| `ORIGINAL` | 自然尺寸，不缩放 |
| `RATIO` | 均匀缩放以**适应**边界内（letter-box）—— **默认** |
| `FIT` | 均匀缩放以**覆盖**边界（可能裁剪） |
| `STRETCH` | 拉伸以精确填充（忽略宽高比） |
| `FIT_WIDTH` / `FIT_HEIGHT` | 适应宽度 / 高度，保持比例 |
| `FIT_HALF_WIDTH` / `FIT_HALF_HEIGHT` | 适应一半宽度 / 高度 |

``

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.image.*;   // Image, ImageException

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

      // 加载 Image 可能抛出 ImageException/IOException — 请处理以免界面崩溃。
      ImageView iv = new ImageView();          // 空（占位符：什么也不绘制）
      try {
         Image capa = new Image("cf/samples/api/ui/books/book1.png");
         iv.image(capa).imageSize(ImageSize.RATIO);
      } catch (ImageException e) {
         System.out.println("Imagem não encontrada, usando placeholder vazio: " + e.getMessage());
      }

      add(LAY_FILL, iv);
   }
}
```

> 下面的片段只展示**核心部分**（放入 `onShow()` 内的内容）。要运行它们，请将其放入上面的 `MainWindow` 骨架中。

## 基本用法
```java
Image capa = new Image("cf/samples/api/ui/books/book1.png");
ImageView iv = new ImageView(capa, ImageSize.RATIO);
container.add(LAY_FILL, iv);
```

## 构造函数
| 构造函数 | 描述 |
|---|---|
| `ImageView()` | 空（`image = null`，`ImageSize.RATIO`） |
| `ImageView(Image image)` | 图像，模式为 `RATIO` |
| `ImageView(Image image, ImageSize imageSize)` | 图像 + 缩放模式 |

## 属性与自定义
| 属性 / 方法 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| `image(Image)` | `ImageView`（链式） | `null` | 更换图像（使缓存/布局失效） |
| `imageSize(ImageSize)` | `ImageView`（链式） | `RATIO` | 定义缩放模式 |
| `alignX(Position)` | `ImageView`（链式） | `CENTER` | 水平对齐（`START`/`CENTER`/`END`） |
| `alignY(Position)` | `ImageView`（链式） | `CENTER` | 垂直对齐 |
| `getImage()` | `Image` | — | 当前图像（或 `null`） |
| `getImageSize()` | `ImageSize` | — | 当前模式 |
| `getAutoWidth()` / `getAutoHeight()` | `int` | — | 图像尺寸 + `ingap`（无图像时为 0） |

## 回调与事件
无。`ImageView` 是非交互式的。

## 状态
没有交互状态。如果 `image == null`，则不绘制任何内容。

### 顶部对齐的覆盖（裁剪）
```java
Image foto = new Image(caminhoFoto);
ImageView avatar = new ImageView(foto, ImageSize.FIT)
   .alignY(Position.START);      // 裁剪时保持顶部可见
container.add(0.4f, avatar);
```

### 运行时更换图像（链式）
```java
ImageView iv = new ImageView();          // 空
container.add(LAY_FILL, iv);
// 之后，加载时：
iv.image(new Image(novoCaminho))
  .imageSize(ImageSize.STRETCH);
```

## 最佳实践
- 给 `ImageView` 一个确定的布局空间（`LAY_FILL` 或分数）—— 缩放模式只有在边界已知时才有意义。
- 当 `Image` 不再使用时，用 `dispose()` 释放它（原生资源 —— 见第 18 章）。
- 在 Web 上，优先使用 `ResizeQuality.FAST`；`ImageView` 的内部缩放已经使用该路径。

## 常见错误
- **混淆 `FIT` 与 `RATIO`：** `RATIO` 做 letter-box（整体适应）；`FIT` 覆盖并可能裁剪。`STRETCH` 会扭曲。
- **期望无图像的 `ImageView` 有自动尺寸：** 当 `image == null` 时，`getAutoWidth/Height()` 返回 `0`。

## 另请参阅
- 领域指南：[`ui/`](/docs/ui) · 食谱：[`cookbook/`](/docs/cookbook)
- 概念（图像、`Paint.image`）：[`concepts/`](/docs/concepts)
- 相关组件：[`Label`](/docs/ui/widgets/label) · [`Button`](/docs/ui/widgets/button)
