Files

150 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ButtonSpinner 按钮微调器
## 概述
按钮微调器(ButtonSpinner)是一个带有上下调整按钮的装饰容器,允许用户通过点击按钮、键盘方向键或鼠标滚轮来触发数值增减操作。它是一个通用的装饰容器——自身不管理数值,只负责将「增加/减少」意图通过 `Spin` 事件传递给外部逻辑。
**ButtonSpinner 是 AtomUI 的扩展控件,在 Ant Design 5.0 中没有直接对应的独立组件**。它的设计灵感来自 Ant Design 的 InputNumber(数字输入框)中的步进按钮区域,但被抽象为一个独立的、可复用的装饰容器。典型使用场景包括:
- 作为 `NumericUpDown` 的内部实现基础
- 为任意内容提供步进增减功能
- 需要上下调整按钮的自定义输入场景
ButtonSpinner 继承自 Avalonia 的 `Spinner` 基类,并融合了 AtomUI 的 Design Token 系统、尺寸系统、样式变体系统和输入控件状态系统,提供与 AtomUI 其他输入类控件一致的视觉体验。
---
## 设计原理
### Avalonia 基础能力
ButtonSpinner 继承自 `Avalonia.Controls.Primitives.Spinner`,该基类提供了以下核心能力:
| 能力 | 说明 |
|---|---|
| `Spin` 事件 | `EventHandler<SpinEventArgs>` — 当用户触发增减操作时引发 |
| `SpinDirection` | 枚举:`Increase` / `Decrease` — 指示增减方向 |
| `ValidSpinDirection` | 位标志枚举:`None` / `Increase` / `Decrease` — 控制哪些方向可用 |
| `Content` / `ContentTemplate` | 内容承载能力(继承自 `ContentControl`) |
### AtomUI 的扩展设计
ButtonSpinner 在 Avalonia 基础上增加了以下 AtomUI 特性:
| 扩展能力 | 实现方式 | 设计动机 |
|---|---|---|
| **三种尺寸** | `ISizeTypeAware` — `SizeType` 属性(Large/Middle/Small) | 对齐 Ant Design 的尺寸系统 |
| **三种样式变体** | `IInputControlStyleVariantAware` — `StyleVariant` 属性(Outline/Filled/Borderless) | 对齐 Ant Design Input 的三种变体 |
| **输入状态** | `IInputControlStatusAware` — `Status` 属性(Error/Warning) | 对齐 Ant Design 的验证状态反馈 |
| **前后缀内容** | `InnerLeftContent` / `InnerRightContent` | 对齐 Ant Design Input 的 prefix/suffix |
| **前后附加组件** | `LeftAddOn` / `RightAddOn`(继承自 `AddOnDecoratedBox`) | 对齐 Ant Design Input 的 addonBefore/addonAfter |
| **操作按钮位置** | `ButtonSpinnerLocation` 枚举(Left/Right) | 灵活控制步进按钮的显示位置 |
| **浮动操作按钮** | `IsButtonSpinnerFloatable` 属性 | 操作按钮在鼠标悬浮时滑入,离开时滑出 |
| **紧凑空间** | `ICompactSpaceAware` 接口 | 在 `Space.Compact` 容器中自动调整布局 |
| **过渡动画** | `IMotionAwareControl` 接口 | 操作按钮的滑入/滑出动画 |
| **键盘/滚轮交互** | 方向键 ↑↓ / 鼠标滚轮 | 多种输入方式触发 Spin |
### 浮动操作按钮(Floatable Handle)
这是 ButtonSpinner 独有的特性:当 `IsButtonSpinnerFloatable="True"` 时,操作按钮平时隐藏,鼠标悬浮在控件上时通过滑动动画显示。该特性的设计目的是在不需要频繁调整数值的场景下减少视觉噪音。
**动画行为:**
- 鼠标进入 → 操作按钮从边缘滑入(带不透明度渐变),同时内容区域向反方向收缩让出空间
- 鼠标离开 → 操作按钮滑出,内容区域恢复原始位置
- 动画使用 `MotionDurationMid` Token 控制时长
---
## 继承关系
```
Avalonia.Controls.ContentControl
└── Avalonia.Controls.Primitives.Spinner (Spin 事件, ValidSpinDirection)
└── AtomUI.Desktop.Controls.ButtonSpinner
(ISizeTypeAware, IInputControlStyleVariantAware,
IInputControlStatusAware, IMotionAwareControl, ICompactSpaceAware)
```
**内部组件关系:**
```
ButtonSpinner
├── ButtonSpinnerDecoratedBox (extends AddOnDecoratedBox)
│ ├── LeftAddOn / RightAddOn ← 外部附加组件
│ ├── InnerLeftContent / InnerRightContent ← 内部前后缀
│ ├── Content ← 用户内容
│ └── SpinnerContent
│ └── ButtonSpinnerHandle ← 操作按钮容器
│ ├── IconButton (IncreaseButton, ↑)
│ └── IconButton (DecreaseButton, ↓)
└── ButtonSpinnerContentPanel (extends DockPanel) ← 内容布局面板
```
**实现的共享接口:**
| 接口 | 作用 |
|---|---|
| `ISizeTypeAware` | 支持 Large/Middle/Small 三种尺寸 |
| `IInputControlStyleVariantAware` | 支持 Outline/Filled/Borderless 三种样式变体 |
| `IInputControlStatusAware` | 支持 Error/Warning 验证状态 |
| `IMotionAwareControl` | 支持 `IsMotionEnabled` 动画控制 |
| `ICompactSpaceAware` | 支持紧凑空间自动布局调整 |
---
## 源码位置
| 层级 | 文件路径 | 说明 |
|---|---|---|
| 控件类 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinner.cs` | 主控件类 |
| 内部控件 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinnerDecoratedBox.cs` | 装饰容器(浮动动画逻辑) |
| 内部控件 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinnerHandle.cs` | 操作按钮容器(自定义渲染边框) |
| 内部控件 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinnerContentPanel.cs` | 内容布局面板 |
| 伪类 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinnerPseudoClass.cs` | 伪类常量 |
| Token 定义 | `src/AtomUI.Desktop.Controls/ButtonSpinner/ButtonSpinnerToken.cs` | 组件级 Design Token |
| 主题模板 | `src/AtomUI.Desktop.Controls/ButtonSpinner/Themes/ButtonSpinnerTheme.axaml` | 控件主题模板 |
| 主题模板 | `src/AtomUI.Desktop.Controls/ButtonSpinner/Themes/ButtonSpinnerHandleTheme.axaml` | 操作按钮主题 |
| 主题模板 | `src/AtomUI.Desktop.Controls/ButtonSpinner/Themes/ButtonSpinnerDecoratedBoxTheme.axaml` | 装饰容器主题 |
| 主题常量 | `src/AtomUI.Desktop.Controls/ButtonSpinner/Themes/ButtonSpinnerThemeConstants.cs` | 模板部件名常量 |
| 主题注册 | `src/AtomUI.Desktop.Controls/ButtonSpinner/Themes/ButtonSpinnerThemes.axaml` | 主题资源注册 |
| Gallery 示例 | `controlgallery/AtomUIGallery/ShowCases/Views/Navigation/ButtonSpinnerShowCase.axaml` | 使用范例 |
---
## 模板结构
```
ButtonSpinner
└── ButtonSpinnerDecoratedBox (PART_DecoratedBox) ← 装饰容器
├── [LeftAddOn] ← 左侧附加组件(可选)
├── InnerBox ← 内部输入区域
│ ├── [InnerLeftContent] ← 前缀(可选)
│ ├── Content ← 用户内容
│ └── [InnerRightContent] ← 后缀(可选)
├── ButtonSpinnerHandle (SpinnerContent) ← 操作按钮区域
│ └── UniformGrid (1列 × 2行)
│ ├── IconButton (PART_IncreaseButton, ↑) ← 增加按钮
│ └── IconButton (PART_DecreaseButton, ↓) ← 减少按钮
└── [RightAddOn] ← 右侧附加组件(可选)
```
### 模板部件常量
| 常量 | 值 | 说明 |
|---|---|---|
| `ButtonSpinnerThemeConstants.DecoratedBoxPart` | `"PART_DecoratedBox"` | 装饰容器部件 |
| `ButtonSpinnerThemeConstants.IncreaseButtonPart` | `"PART_IncreaseButton"` | 增加按钮部件 |
| `ButtonSpinnerThemeConstants.DecreaseButtonPart` | `"PART_DecreaseButton"` | 减少按钮部件 |
| `ButtonSpinnerThemeConstants.SpinnerHandlePart` | `"PART_SpinnerHandle"` | 操作手柄部件 |
### 交互行为
| 触发方式 | 条件 | 行为 |
|---|---|---|
| 点击增加按钮 | `AllowSpin == true` | 触发 `Spin` 事件,方向 `Increase` |
| 点击减少按钮 | `AllowSpin == true` | 触发 `Spin` 事件,方向 `Decrease` |
| 键盘 ↑ 键 | `AllowSpin == true`,非 XY 导航模式 | 触发 `Spin` 事件,方向 `Increase` |
| 键盘 ↓ 键 | `AllowSpin == true`,非 XY 导航模式 | 触发 `Spin` 事件,方向 `Decrease` |
| 鼠标滚轮向上 | `AllowSpin == true`,控件获得键盘焦点 | 触发 `Spin` 事件,方向 `Increase` |
| 鼠标滚轮向下 | `AllowSpin == true`,控件获得键盘焦点 | 触发 `Spin` 事件,方向 `Decrease` |