# 样式与主题

> 外观模型 —— Skin 是结构，Theme 是按模式划分的语义角色 —— 以及运行时主题切换。

Source: https://crossfly.dev/zh/docs/concepts/styling-and-theming-model — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 样式与主题

CrossFly 中的外观可以归结为框架自身的一句助记词：

> **Skin = 结构 / 渲染器 · Theme = 按模式划分的语义角色。**

三个不同的职责相互协作。

## 1. 按状态划分的样式（default / focused / pressed）
每个 `Component` 都可以拥有**最多三种样式**，框架会根据交互在每一帧
选择正确的那一种。这就是为什么一个按钮被按下时会"下沉"，而你无需编写任何动画。
```java
comp.style(normal).focusedStyle(focado).pressedStyle(apertado);
```

## 2. `Skin` —— 形态工厂
`Skin` 定义**结构**：圆角半径、边框粗细、间距、默认图标。有
`MaterialSkin`、`IOSSkin`、`FlutterSkin`。自定义 `Skin` 会覆盖**形态/间距** —— 但从不
覆盖颜色。更换全局 `Skin` 会为所有组件重新"穿衣"。

## 3. `Theme` + `ColorScheme` —— 语义角色
**颜色**来自角色（PRIMARY、SURFACE、ON_SURFACE、ERROR、TITLE、HINT……），它们被解析到当前的**亮色/暗色
模式**，其来源是一个从**种子色**生成的 `ColorScheme`（Material You）。
```java
Styles.theme(0xFF6750A4, ThemeMode.DARK);   // 一次调用即在暗色模式下为一切设定主题
```

## 最强大之处：在运行时切换主题而无需重建 UI
这里有一个微妙之处，让亮色/暗色模式变得轻而易举：

- 样式的颜色不是"冻结"的值 —— 它们是 **`PalColor`**，是对调色板的**活**
  引用。
- 存在一个**全局样式版本计数器**（`styleVersion`）。当应用新的方案 /
  切换模式时，框架会**递增版本号**并在所有打开的窗口上重新应用主题 ——
  每个基于 `PalColor` 的样式都会**在下一帧重新解析其颜色**。没有任何组件被
  销毁再重建。

作为补充，那些样式会因模式而**改变形态**的组件会注册如何自我重新样式化
（`onRestyle`/`styled`），而 `restyle()` 会就地重新应用子树：
```java
Label titulo = new Label("Bem-vindo").styled(() -> Styles.theme().label(LabelRole.TITLE));
// ...切换模式时，框架重新评估该 provider 并重新着装，无需重建 Label。
Styles.toggleDarkMode();
```

## 为什么采用这种架构
- **将形态（Skin）与颜色（Theme）分离**，让你可以独立更换视觉标识与
  色板 —— 并在不改动 Skin 的情况下适配亮色/暗色。
- **`PalColor` + 版本**把"切换主题"从"重建整棵树"变成了"在下一帧
  重新解析颜色" —— 廉价且无闪烁。

## 参见
- 应用：[主题与样式](/docs/ui/theming) · [亮色/暗色模式](/docs/ui/theming/dark-mode)
- 下一篇：[生命周期](/docs/concepts/lifecycle)
