# 明/暗模式

> 实时切换主题而无需重建 UI — setDarkMode + onRestyle/styled/restyle。

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

# 明/暗模式

CrossFly **实时且原地**在明色与暗色之间切换 — 无需重建界面。关键在于
`Styles.setDarkMode(...)` 与那些能从主题**重新解析**的样式相结合。

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

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // Styles、ThemeMode、LabelRole

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      Styles.setColorScheme(0xFF6750A4, ThemeMode.LIGHT);   // 基础调色板（跟随浅色/深色）
      setLayout(new VerticalLayout());

      // styled(...) 在每次切换主题时重新计算样式（按模式自动换肤）
      Label titulo = new Label("Bem-vindo")
         .styled(() -> Styles.theme().label(LabelRole.TITLE));
      add(LAY_AUTO, titulo);

      // Switch 切换模式；setDarkMode 自动为整个已打开的 UI 重新换肤。
      Switch alternar = new Switch("Modo escuro");
      alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked()));
      add(LAY_AUTO, alternar);
   }
}
```
> 下面的片段只展示了**核心部分**（放入 `onShow()` 内部的内容）。要运行它们，请将其放入上面的 `MainWindow` 骨架中。

## 自动的方式（推荐）
1. 在样式中使用**主题的 `PalColor`**（`Styles.textColor`、`cs.surface`）— 它们会自动重新解析。
2. 调用 `setDarkMode(...)`：
```java
Styles.toggleDarkMode();              // 在浅色 ↔ 深色间切换
Styles.setDarkMode(true);             // 强制深色
boolean escuro = Styles.isDarkMode(); // 当前状态
```
`setDarkMode(...)` 已经会自动**在所有打开的窗口上重新应用主题**（内部会触发
`restyleAll()`），因此绑定到 `PalColor` 的样式无需任何额外代码即可改变颜色。

## 依赖模式的样式 → `styled(...)` / `onRestyle(...)`
当样式随模式**改变形态**（而不仅仅是颜色）时，请注册组件应如何重新设置样式。回调会在当时运行一次，
并在每次切换主题时再次运行：
```java
Label titulo = new Label("Bem-vindo")
   .styled(() -> Styles.theme().label(LabelRole.TITLE));   // 每次切换主题时重新计算

// 用于样式之外的逻辑（切换图标字形、图表颜色等）：
Label l = new Label("Status");
l.onRestyle(() -> l.style(Styles.isDarkMode() ? estiloEscuro : estiloClaro));
```

## 手动对子树重新换肤
如果你以非全局的方式改变了主题（例如仅一个面板），请强制重新应用：
```java
window.restyle();   // 重新执行整棵树的所有 onRestyle 并重绘，无需重建组件
```

## 完整流程
```java
Switch alternar = new Switch("Modo escuro");
alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked()));  // 整个 UI 随之更新
```

## 最佳实践
- 相比固定颜色，优先使用**主题的 `PalColor`** — 暗色模式将变为自动生效。
- 对于随模式改变结构的样式，使用 **`styled(...)`**（比 `onRestyle` 更简洁）。
- 在**构建**样式时用 `Styles.isDarkMode()` / `Styles.themeMode()` 读取模式。

## 常见错误
- 保存固定颜色（`0xFF...`），之后不得不手动重建界面来适配暗色。
- 切换主题时重建整个 UI — 请使用 `restyle()`/`styled(...)` 并复用组件。

## 另请参阅
- [配色方案](/docs/ui/theming/color-schemes) · [组件样式设置](/docs/ui/theming/styling-components) · [Skins](/docs/ui/theming/skins)
