# LabelItem 和 CheckLabelItem

> 现成的列表项卡片 —— 仅标签（SINGLE）或复选框 + 标签（MULTIPLE）。

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

# LabelItem 和 CheckLabelItem

`LabelItem` 和 `CheckLabelItem` 是现成的列表项“卡片”，位于 `dev.crossfly.ui.listitem` 包中。二者都继承自 `Component`，并由 [`ListView`](/docs/ui/widgets/listview) 在内部使用：

- **`LabelItem`** —— 单个带自动换行的 `Label`。用于 `SINGLE` 模式。
- **`CheckLabelItem`** —— 一个 `Option`（复选框）+ `Label`。用于 `MULTIPLE` 模式。

通常你**不会**直接实例化它们 —— `ListView` 会根据 `ItemType` 创建正确的类型。当你手动构建一个列表并希望获得相同的卡片外观/行为时才使用它们。

> 🟡 · **包：** `dev.crossfly.ui.listitem` · **继承自：** `Component` · **样式：** `ComponentStyle`（卡片）+ `LabelStyle`（标签）

## 何时使用
- 手动构建列表（在 `ListView` 之外），复用默认的卡片视觉效果。
- 需要一个外观与框架列表一致的独立可点击项。

## 何时不要使用
- 现成的选择列表 → 让 [`ListView`](/docs/ui/widgets/listview) 为你创建各项。
- 带图片/多字段的丰富行 → 构建你自己的 `Component`（或使用 `ListView` 的 `itemFactory`）。

## 外观
带有选择主题的背景/边框（`selectionCardBackColor`/`selectionCardBorderColor`）、`pressable`、带默认间距的卡片。`LabelItem` 以 START/CENTER 对齐显示文本；`CheckLabelItem` 将复选框放在左侧（宽度自动），标签占 90%。

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.listitem.*;   // LabelItem, CheckLabelItem

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

      // 手动构建、复用标准卡片外观的列表。
      Component lista = new Component();
      lista.setLayout(new GridLayout(Position.CENTER, Position.START));
      lista.setScrollable(ScrollDirection.VERTICAL);

      String[] linhas = {"Alpha", "Beta", "Gamma"};
      for (int i = 0; i < linhas.length; i++) {
         LabelItem item = new LabelItem(linhas[i], i);
         final int idx = i;
         item.onAction(e -> System.out.println("selecionou " + idx));
         lista.add(.95f, item);
      }

      CheckLabelItem termos = new CheckLabelItem("Aceito os termos", linhas.length);
      termos.onAction(e -> { termos.toggle(); System.out.println(termos.isChecked()); });
      lista.add(.95f, termos);

      add(LAY_FILL, lista);   // 列表使用 LAY_FILL（占满高度）
   }
}
```

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

## 基本用法
```java
// LabelItem — 单一标签的可点击项
LabelItem item = new LabelItem("Linha", 0);
item.onAction(e -> System.out.println("clicou " + item.index));
layout.add(.95f, item);

// CheckLabelItem — 带复选框的项
CheckLabelItem c = new CheckLabelItem("Aceito os termos", 0);
c.onAction(e -> { c.toggle(); System.out.println(c.isChecked()); });
layout.add(.95f, c);
```

### LabelItem
| 构造函数 | 描述 |
|---|---|
| `LabelItem(String text, int index)` | 默认样式 |
| `LabelItem(String text, int index, ComponentStyle cardStyle, LabelStyle labelStyle)` | 自定义样式 |

### CheckLabelItem
| 构造函数 | 描述 |
|---|---|
| `CheckLabelItem(String text, int index)` | 默认样式 |
| `CheckLabelItem(String text, int index, ComponentStyle cardStyle)` | 自定义卡片样式 |

字段 `text` 和 `index` 为 `public final`。

## 属性与自定义
| 成员 | 类 | 作用 |
|---|---|---|
| `text` (final) | 二者 | 项的文本 |
| `index` (final) | 二者 | 项在列表中的索引 |
| `getAutoHeight()` | 二者 | 首选高度（标签/复选框 + ingap） |
| `isChecked()` | `CheckLabelItem` | 复选框的当前状态 |
| `setChecked(boolean)` | `CheckLabelItem` | 设置状态 |
| `toggle()` | `CheckLabelItem` | 切换状态 |
| `getCheck()` | `CheckLabelItem` | 访问内部的 `Option` |
| `defaultItemStyle()` (static) | 二者 | 可复用的卡片样式（选择卡片，`pressable`） |
| `defaultLabelStyle()` (static) | `LabelItem` | 可复用的标签样式 |

## 回调与事件
| 回调 | 触发时机 |
|---|---|
| `onAction(Action)` | 点击卡片时（继承自 `Component`） |

在 `CheckLabelItem` 中，点击**不会**自动切换复选框 —— 请在你的回调里调用 `toggle()`（这正是 `ListView` 内部所做的）。

## 状态
- **pressed** —— 二者默认均为 `pressable`（触摸反馈）。
- **checked** —— 仅 `CheckLabelItem`：由 `setChecked`/`toggle` 控制，可用 `isChecked` 查询。

### 复用卡片视觉的手动列表
```java
Component lista = new Component();
lista.setLayout(new GridLayout(Position.CENTER, Position.START));
lista.setScrollable(ScrollDirection.VERTICAL);
String[] linhas = {"Alpha", "Beta", "Gamma"};
for (int i = 0; i < linhas.length; i++) {
   LabelItem item = new LabelItem(linhas[i], i);
   final int idx = i;
   item.onAction(e -> System.out.println("selecionou " + idx));
   lista.add(.95f, item);
}
layout.add(LAY_FILL, lista);
```

### 带自定义卡片的 CheckLabelItem
```java
ComponentStyle card = CheckLabelItem.defaultItemStyle()
   .copy()
   .backColor(0xFFF5F5F5);
CheckLabelItem opt = new CheckLabelItem("Receber notificações", 0, card);
opt.setChecked(true);
opt.onAction(e -> { opt.toggle(); });
layout.add(.95f, opt);
```

## 最佳实践
- 复用 `defaultItemStyle()` / `defaultLabelStyle()`（配合 `.copy()`），以保持与框架列表的视觉一致性。
- 在 `GridLayout(CENTER, START)` 中以 `.95f` 宽度添加各项，以重现 `ListView` 的间距。

## 常见错误
- **期望 `CheckLabelItem` 在点击时自动切换复选框** —— 请在 `onAction` 中调用 `toggle()`。
- **在已经使用 `ListView` 时还实例化这些项** —— `ListView` 已经会根据 `ItemType` 创建正确的类型。

## 另请参阅
- 领域指南：[`ui/`](/docs/ui) · 实用配方：[`cookbook/`](/docs/cookbook)
- 相关组件：[`ListView`](/docs/ui/widgets/listview) · [`ListViewWindow`](/docs/ui/widgets/listviewwindow)
