10 KiB
Slider 滑动条
概述
滑动条(Slider)用于在给定的数值范围内选择一个值或一段范围。支持水平/垂直方向、刻度标记(Marks)、刻度吸附、范围选择(双滑块)、自定义值格式化、值包含模式等。
AtomUI 的 Slider 控件完整实现了 Ant Design 5.0 Slider 的设计规范,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。
设计原理
Ant Design 的滑动条设计哲学
Ant Design 对滑动条的定位是:「当用户需要在数值区间/自定义区间内进行选择时,可为连续或离散值」。滑动条相比纯数字输入框更加直观,用户可以通过拖拽快速感知值的相对位置。
核心设计维度:
| 维度 | 设计意图 | 典型用途 |
|---|---|---|
| 单值模式 | 在连续数值范围内选择一个值 | 音量控制、亮度调节、透明度设置 |
| 范围模式(Range) | 通过双滑块选择一段范围 | 价格区间、时间段筛选 |
| 刻度标记(Marks) | 在轨道上标注关键刻度点 | 温度选择、评分等级 |
| 刻度吸附(Step) | 滑块自动吸附到最近刻度 | 离散值选择 |
| 值包含(Included) | 控制轨道覆盖部分是否高亮 | 强调/弱化选中范围 |
| 方向 | 水平/垂直两个方向 | 适配不同布局场景 |
| Tooltip | 拖拽时显示当前值 | 精确反馈 |
Avalonia RangeBase 基础能力
AtomUI 的 Slider 继承自 Avalonia 的 RangeBase(而非 Avalonia 内置的 Slider),直接基于 RangeBase 从头构建。RangeBase 提供:
| 属性 | 说明 |
|---|---|
Minimum |
最小值 |
Maximum |
最大值 |
Value |
当前值 |
SmallChange |
小步进值 |
LargeChange |
大步进值 |
AtomUI 的 Slider 不继承 Avalonia 内置 Slider,避免了其有限的功能限制(如不支持范围模式、刻度标记等)。
AtomUI 的扩展设计
| 扩展能力 | 实现方式 | 设计动机 |
|---|---|---|
| 范围模式 | IsRangeMode + RangeValue |
双滑块范围选择,对齐 Ant Design range |
| 方向 | Orientation |
水平/垂直两个方向 |
| 刻度标记 | Marks 属性(List<SliderMark>) |
自定义标签、样式的刻度标记 |
| 刻度吸附 | IsSnapToTickEnabled + TickFrequency |
滑块自动吸附到最近刻度 |
| Tooltip 格式化 | ValueFormatTemplate |
自定义 Tooltip 显示格式 |
| 值包含 | Included |
控制轨道覆盖部分是否高亮 |
| 方向反转 | IsDirectionReversed |
反转滑动方向 |
| 波纹动画 | IsWaveSpiritEnabled |
滑块聚焦时的波纹效果 |
| 表单集成 | IFormItemAware |
可参与 FormItem 验证流程 |
| 无障碍 | SliderAutomationPeer |
符合 Avalonia 自动化标准 |
| 自绘滑块 | SliderThumb.Render() |
精确控制圆形滑块和 outline 环的绘制 |
| Design Token | SliderToken + RegisterTokenResourceScope |
所有视觉值从全局/组件级 Token 派生 |
功能详解
单值模式
默认模式。通过 Value 属性获取/设置当前值,轨道高亮从 Minimum 到 Value 的部分:
<atom:Slider Minimum="0" Maximum="100" Value="50" />
范围模式(IsRangeMode)
启用 IsRangeMode 后,出现双滑块,通过 RangeValue 控制范围。RangeValue 是一个 SliderRangeValue 记录结构体,包含 StartValue 和 EndValue:
<atom:Slider IsRangeMode="True" RangeValue="20, 80" Maximum="100" />
轨道高亮 StartValue 到 EndValue 之间的部分。拖拽时自动判断离哪个滑块更近。
刻度标记(Marks)
通过 Marks 属性定义关键刻度点。每个 SliderMark 包含标签文字和对应值,还可以自定义颜色、字体样式和字重:
slider.Marks = new List<SliderMark>
{
new("0°C", 0),
new("26°C", 26),
new("37°C", 37),
new("100°C", 100) { LabelBrush = Brushes.Red, LabelFontWeight = FontWeight.Bold }
};
刻度标记在轨道上显示为小圆点,标签文字渲染在刻度下方(水平)或右侧(垂直)。点击标记可直接跳转到对应值。
刻度吸附(Snap to Tick)
设置 TickFrequency 定义刻度间隔,配合 IsSnapToTickEnabled=True 可让滑块只停留在刻度位置:
<atom:Slider TickFrequency="10" IsSnapToTickEnabled="True" Maximum="100" />
值包含(Included)
Included 属性控制轨道覆盖部分是否高亮:
true(默认):高亮Minimum到Value(或StartValue到EndValue)之间的轨道false:轨道不高亮,只显示刻度标记和滑块位置
Tooltip 格式化
通过 ValueFormatTemplate 自定义拖拽时 Tooltip 的显示格式,使用 string.Format 语法:
<atom:Slider ValueFormatTemplate="\{0\}%" Value="50" Maximum="100" />
<!-- Tooltip 显示 "50%" -->
键盘导航
Slider 支持完整的键盘操作:←/↓ 减少、→/↑ 增加、PageUp/PageDown 大步进、Home/End 跳转极值。
自绘滑块(SliderThumb)
SliderThumb 通过重写 Render 方法直接绘制圆形滑块和 outline 环,而非使用模板内控件。这样可以精确控制:
- 滑块圆形大小(正常态 / 悬浮态)
- 边框粗细(正常态 / 悬浮态)
- Outline 环的颜色和厚度
- 平滑的过渡动画
轨道自绘(SliderTrack)
SliderTrack 负责整个轨道区域的渲染和布局,包括:
- 轨道底层(Rail):灰色背景条
- 已覆盖部分(Track Bar):主色高亮条
- 刻度标记点和标签文字
- 滑块位置计算和布局
与 Ant Design 规范的对齐程度
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|---|---|---|---|
| 基本滑动条 | ✅ <Slider /> |
✅ <atom:Slider /> |
✅ 完全对齐 |
范围模式 range |
✅ 布尔 | ✅ IsRangeMode + RangeValue |
✅ 完全对齐 |
禁用 disabled |
✅ 布尔 | ✅ IsEnabled |
✅ 完全对齐 |
垂直 vertical |
✅ 布尔 | ✅ Orientation="Vertical" |
✅ 完全对齐 |
刻度标记 marks |
✅ 对象 | ✅ Marks 属性 |
✅ 完全对齐 |
刻度吸附 step |
✅ 数字/null | ✅ IsSnapToTickEnabled + TickFrequency |
✅ 完全对齐 |
包含 included |
✅ 布尔 | ✅ Included |
✅ 完全对齐 |
Tooltip tooltip |
✅ formatter | ✅ ValueFormatTemplate |
✅ 完全对齐 |
min/max |
✅ 数字 | ✅ Minimum/Maximum |
✅ 完全对齐 |
反转方向 reverse |
✅ 布尔 | ✅ IsDirectionReversed |
✅ 完全对齐 |
继承关系
Avalonia.Controls.Primitives.RangeBase
└── AtomUI.Desktop.Controls.Slider (IMotionAwareControl, IFormItemAware)
辅助类型
Avalonia.Controls.Primitives.TemplatedControl
├── AtomUI.Desktop.Controls.SliderTrack ← 轨道控件(自绘轨道、刻度标记、滑块布局)
└── AtomUI.Desktop.Controls.SliderThumb ← 滑块手柄(自绘圆形 + outline 环,可拖拽)
各层级职责划分:
| 层级 | 提供的能力 |
|---|---|
RangeBase(Avalonia) |
Minimum/Maximum/Value/SmallChange/LargeChange 基础范围属性 |
Slider |
范围模式、刻度吸附、Marks、Tooltip 格式化、Included、方向、键盘导航、表单集成、Token 注册 |
SliderTrack |
轨道自绘渲染(Rail + Track Bar + Mark 点/标签)、滑块位置计算和布局、指针交互 |
SliderThumb |
滑块手柄自绘(圆形 + 边框 + outline 环)、拖拽事件(DragStarted/DragDelta/DragCompleted)、过渡动画 |
实现的共享接口:
| 接口 | 定义位置 | 作用 |
|---|---|---|
IMotionAwareControl |
AtomUI.Controls.Shared |
控制过渡动画开关(IsMotionEnabled) |
IFormItemAware |
AtomUI.Controls.Shared |
参与表单验证流程;单值模式表单值为 double,范围模式为 SliderRangeValue |
注意:Slider 全部定义在
AtomUI.Desktop.Controls中,不存在AtomUI.Controls基类层的设备无关抽象。
源码位置
| 层级 | 文件路径 | 说明 |
|---|---|---|
| 控件类 | src/AtomUI.Desktop.Controls/Slider/Slider.cs |
Slider 主控件(759 行) |
| 轨道 | src/AtomUI.Desktop.Controls/Slider/SliderTrack.cs |
内部轨道控件(1092 行) |
| 滑块 | src/AtomUI.Desktop.Controls/Slider/SliderThumb.cs |
可拖拽手柄(255 行) |
| 无障碍 | src/AtomUI.Desktop.Controls/Slider/SliderAutomationPeer.cs |
Slider Automation Peer |
| Token | src/AtomUI.Desktop.Controls/Slider/SliderToken.cs |
组件级 Design Token |
| 主题 | src/AtomUI.Desktop.Controls/Slider/Themes/SliderTheme.axaml |
Slider ControlTheme |
| 主题 | src/AtomUI.Desktop.Controls/Slider/Themes/SliderThumbTheme.axaml |
SliderThumb ControlTheme |
| 主题 | src/AtomUI.Desktop.Controls/Slider/Themes/SliderTrackTheme.axaml |
SliderTrack ControlTheme |
| 主题常量 | src/AtomUI.Desktop.Controls/Slider/Themes/SliderThemeConstants.cs |
模板部件名称常量 |
| Gallery | controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/SliderShowCase.axaml |
使用范例 |
模板结构
Slider
Slider 的模板非常简洁,核心是一个 SliderTrack:
SliderTrack#PART_Track
├── Rail(轨道底层,灰色背景) ← SliderTrack 自绘
├── Track Bar(已覆盖部分,主色高亮) ← SliderTrack 自绘
├── Mark Dots(刻度标记圆点) ← SliderTrack 自绘
├── Mark Labels(刻度标注文字) ← SliderTrack 自绘
├── SliderThumb#PART_StartThumb ← 起始滑块(单值模式 / 范围起点)
└── SliderThumb#PART_EndThumb ← 结束滑块(仅范围模式可见)
SliderThumb
SliderThumb 不使用模板,而是通过 Render() 直接绘制:
- 白色底圆 + 主色边框 = 滑块主体
- 主色半透明 outline 环 = 聚焦/悬浮效果
模板部件常量
| 常量 | 值 | 说明 |
|---|---|---|
SliderThemeConstants.TrackPart |
"PART_Track" |
轨道控件 |
SliderThemeConstants.StartThumbPart |
"PART_StartThumb" |
起始滑块 |
SliderThemeConstants.EndThumbPart |
"PART_EndThumb" |
结束滑块(范围模式) |