# Option

> 带交叉淡入淡出动画的复选框/单选框 —— 单独使用时为复选框，在 Group 中为单选框。

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

# Option

`Option` 是一个标记控件，在“on”和“off”图标之间通过交叉淡入淡出动画切换，并带有可选标签。**在组之外**它表现为**复选框**（独立勾选/取消）；**在 [`group`](/docs/ui/widgets/group) 之内**它表现为**单选按钮**（互斥）。复选框与单选框的视觉差异来自样式（`Styles.check()` vs `Styles.radio()`），而非类本身。

> 🟢 · **包：** `dev.crossfly.ui` · **继承自：** `Component`（实现 `Checkable`、`AlphaAnimation.Animate`）· **样式：** `OptionStyle`

## 何时使用
- 单个复选框或一组独立的复选框（“我接受条款”）。
- 一组小型的、同时可见的互斥选项（单选），通过 [`group`](/docs/ui/widgets/group)。

## 何时不要使用
- 需要带开关隐喻的开/关 → 使用 [`switch`](/docs/ui/widgets/switch)。
- 需要许多互斥选项（节省空间）→ 使用 [`dropdown`](/docs/ui/widgets/dropdown)。

## 外观
on/off 图标（来自 `OptionStyle`）+ 可选标签。图标对齐（`iconAlignH`/`iconAlignV`）决定其所在的一侧；文本占据对侧（`textAlignH`/`textAlignV`）。`progress`（0→1）在过渡期间混合两个图标的透明度。

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // Styles.check() / Styles.radio()

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

      Label saida = new Label("Escolha uma opção");
      add(LAY_AUTO, saida);

      // 独立复选框（无分组）
      Option aceito = new Option("Aceito os termos").style(Styles.check().copy());
      aceito.onAction(c -> saida.setText("Termos: " + (aceito.checked ? "aceitos" : "recusados")));
      add(LAY_AUTO, aceito);

      // Radio：Group 内三个互斥选项
      Group pagamento = new Group();
      Option cartao = new Option("Cartão").style(Styles.radio().copy()).group(pagamento).checked(true);
      Option boleto = new Option("Boleto").style(Styles.radio().copy()).group(pagamento);
      Option pix    = new Option("Pix").style(Styles.radio().copy()).group(pagamento);

      Component.Action mostra = c -> {
         String sel = cartao.isChecked() ? "Cartão" : boleto.isChecked() ? "Boleto" : "Pix";
         saida.setText("Pagamento: " + sel);
      };
      cartao.onAction(mostra);
      boleto.onAction(mostra);
      pix.onAction(mostra);

      add(LAY_AUTO, cartao);
      add(LAY_AUTO, boleto);
      add(LAY_AUTO, pix);
   }
}
```

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

## 基本用法
```java
Option aceito = new Option("Aceito os termos");
aceito.style(Styles.check().copy());
aceito.checked(true);                                   // 初始选中
aceito.onAction(c -> System.out.println("aceito: " + aceito.checked));
container.add(LAY_AUTO, aceito);
```

## 构造函数
| 构造函数 | 描述 |
|---|---|
| `Option()` | 未勾选，无标签。 |
| `Option(String text)` | 未勾选，带标签。 |

## 属性与自定义
| 属性 / 方法 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| `text(String)` | `Option`（流式） | `null` | 设置标签。 |
| `checked(boolean)` | `Option`（流式） | `false` | **无**动画的初始状态；通知组。 |
| `setChecked(boolean)` | `void` | — | **带**动画（交叉淡入淡出）的状态；通知组。 |
| `toggle()` | `void` | — | 切换状态（遵循组的规则）。 |
| `checked` | `boolean`（字段） | `false` | 当前逻辑状态（可直接读/写）。 |
| `.group(Group)` | `Option`（流式） | — | 关联到一个 [`group`](/docs/ui/widgets/group) → 变为单选框。 |

## 回调与事件
| 回调 | 触发时机 |
|---|---|
| `onAction(Action)` | 在 `onTouchUp` 时，**仅当** `checked` 发生变化。 |

## 状态
- **checked / unchecked**：通过 `checked(boolean)`（无动画）或 `setChecked(boolean)`（交叉淡入淡出）。也可以直接给公有字段 `checked` 赋值。
- **radio（在组中）**：`toggle()` 阻止取消已选中的项；选中另一项会自动取消当前项。

### 单选：Group 中的三个互斥选项
```java
Group g = new Group();

Option a = new Option("Opção A").style(Styles.radio().copy()).group(g).checked(true);
Option b = new Option("Opção B").style(Styles.radio().copy()).group(g);
Option c = new Option("Opção C").style(Styles.radio().copy()).group(g);

container.add(LAY_AUTO, a);
container.add(LAY_AUTO, b);
container.add(LAY_AUTO, c);
// 选中任意一个会自动取消选中其余的。
```

## 最佳实践
- 对于单选框，在**所有**选项上调用 `.group(g)`，并用 `Styles.radio()` 区分；对于复选框，省略组并使用 `Styles.check()`。
- 初始状态优先使用 `checked(boolean)` 而非 `checked` 字段：它还会调整 `progress` 并通知组。

## 常见错误
- 在某个选项上忘记 `.group(g)`：没有组它们就会变成独立的复选框（没有互斥）。
- 期望通过点击“取消”一个单选框：在组内 `toggle()` 会阻止这一点。

## 另请参阅
- 领域指南：[`ui/`](/docs/ui) · 实用配方：[`cookbook/`](/docs/cookbook)
- 概念（按状态的样式）：[`concepts/`](/docs/concepts)
- 相关组件：[`group`](/docs/ui/widgets/group) · [`switch`](/docs/ui/widgets/switch) · [`dropdown`](/docs/ui/widgets/dropdown)
