12 KiB
Tooltip 文字提示
概述
文字提示(ToolTip)是一种轻量级的浮层提示组件,在鼠标悬浮到目标元素上时显示提示信息。它是图形界面中最常见的辅助信息展示方式——无需用户主动操作,只要将鼠标移至目标区域即可获得上下文提示。常见用途包括:解释图标含义、补充说明按钮功能、展示被截断的完整文本等。
AtomUI 的 ToolTip 控件完整复刻了 Ant Design 5.0 Tooltip 的设计规范,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。
注意:AtomUI 中该控件命名为
ToolTip,通过附加属性方式使用(atom:ToolTip.Tip="xxx"),可附加到任意控件上。
设计原理
Ant Design 的 Tooltip 设计哲学
Ant Design 对 Tooltip 的定位是:「简单的文字提示气泡框」。它是最轻量的信息提示方式,相比 Popover(气泡卡片)和 Popconfirm(气泡确认框)更简洁、更专注。
Ant Design 的 Tooltip 设计原则:
| 原则 | 说明 |
|---|---|
| 轻量 | 仅承载简短文字,不建议放置复杂内容或交互控件 |
| 非干扰 | 悬浮触发、离开消失,不阻塞用户操作流程 |
| 辅助性 | 作为补充信息存在,不承载核心信息 |
| 上下文感知 | 通过箭头和定位明确关联目标元素 |
Ant Design Tooltip 的核心特性:
- 12 种弹出方向:Top、Bottom、Left、Right 及各方向的对齐变体
- 箭头指示器:明确指向目标元素,帮助用户建立视觉关联
- 预设颜色与自定义颜色:支持使用调色板颜色或任意自定义颜色
- 延迟控制:通过
mouseEnterDelay/mouseLeaveDelay防抖,避免频繁弹出
Avalonia ToolTip 基础能力
Avalonia 框架内置了基础的 ToolTip 支持(Avalonia.Controls.ToolTip),提供简单的文字提示功能。AtomUI 的 ToolTip 是完全独立的实现,不继承 Avalonia 内置 ToolTip,而是继承自 ContentControl 并结合自定义的 ToolTipService 实现完整的提示逻辑。
AtomUI ToolTip 与 Avalonia 内置 ToolTip 的对比:
| 特性 | Avalonia 内置 ToolTip | AtomUI ToolTip |
|---|---|---|
| 箭头指示器 | ❌ 不支持 | ✅ 支持(ArrowDecoratedBox) |
| 弹出方向 | 基础方向 | 12 种精确方向 |
| 预设颜色 | ❌ 不支持 | ✅ Ant Design 14 色调色板 |
| 自定义颜色 | ❌ 不支持 | ✅ 任意 Color |
| 弹出/关闭动画 | ❌ 无 | ✅ Motion 动画系统 |
| Design Token | ❌ 无 | ✅ 完整 Token 集成 |
| 阴影效果 | ❌ 无 | ✅ Token 驱动的阴影 |
| 箭头居中指向 | ❌ 不支持 | ✅ IsPointAtCenter |
AtomUI 的实现设计
AtomUI 的 ToolTip 通过附加属性模式工作——不需要将 ToolTip 作为控件放到可视树中,而是通过 ToolTip.Tip 附加属性将提示信息关联到任意目标控件上。当鼠标悬浮到目标控件时,ToolTipService 负责创建 ToolTip 实例并通过 Popup 弹出。
| 功能 | 实现方式 | 设计动机 |
|---|---|---|
| 附加属性模式 | ToolTip.Tip 附加属性 |
任何控件都可以添加 Tooltip,无需修改控件模板 |
| 12 种弹出方向 | Placement 附加属性 + PopupUtils |
全方位定位,自动计算锚点和重力方向 |
| 箭头指示器 | ArrowDecoratedBox 内部控件 |
通过几何绘制的三角箭头明确指向目标元素 |
| 箭头居中指向 | IsPointAtCenter + 偏移计算 |
箭头精确指向目标中心,而非气泡边缘 |
| 预设颜色 | PresetColor + PresetPrimaryColor 调色板 |
使用 Ant Design 调色板的 14 种标准颜色 |
| 自定义颜色 | Color 附加属性 |
任意背景色,满足品牌定制需求 |
| 延迟显示 | ShowDelay / BetweenShowDelay + DispatcherTimer |
防抖,避免鼠标快速滑过时频繁弹出 |
| 位置翻转 | Popup.PositionFlipped 事件处理 |
当空间不足时自动翻转方向,箭头随之调整 |
| 弹出/关闭动画 | MotionAwareOpen / MotionAwareClose |
平滑的淡入淡出动画,可通过 IsMotionEnabled 控制 |
| Design Token | ToolTipToken + RegisterTokenResourceScope |
所有视觉值从 Token 派生,支持主题切换 |
功能详解
附加属性使用模式
ToolTip 通过附加属性附加到任意控件上,核心附加属性包括:
atom:ToolTip.Tip:设置提示内容(可以是字符串,也可以是任意控件)atom:ToolTip.Placement:设置弹出方向(默认Top)atom:ToolTip.IsShowArrow:是否显示箭头(默认true)
当 Tip 为字符串时,ToolTip 内部通过 StringToTextBlockConverter 自动将字符串转换为 TextBlock,并设置自动换行(TextWrapping="Wrap")。
12 种弹出方向
通过 Placement 附加属性(PlacementMode 枚举)控制 ToolTip 的弹出位置:
TL Top TR
┌──────────┐
LT │ │ RT
Left │ Target │ Right
LB │ │ RB
└──────────┘
BL Bottom BR
每种方向对应不同的锚点(PlacementAnchor)和重力(PlacementGravity)计算。当目标控件靠近屏幕边缘导致空间不足时,Popup 会自动翻转方向,ToolTip 通过 PopupFlippedEventArgs 事件同步调整箭头位置。
箭头控制
箭头由内部的 ArrowDecoratedBox 控件绘制,提供三种模式:
| 模式 | 属性设置 | 效果 |
|---|---|---|
| 显示箭头 | IsShowArrow="True"(默认) |
箭头指向目标控件方向的边缘 |
| 隐藏箭头 | IsShowArrow="False" |
不显示箭头,仅显示气泡框 |
| 箭头居中 | IsShowArrow="True" + IsPointAtCenter="True" |
箭头精确指向目标控件的中心点 |
注意:在某些弹出方向组合下(如
PlacementAnchor和PlacementGravity不兼容),箭头会被自动禁用。这通过PopupUtils.CanEnabledArrow()判断。
颜色系统
ToolTip 提供三层颜色控制,按优先级从高到低:
- 预设颜色(
PresetColor):使用 Ant Design 调色板的 14 种标准颜色(Blue、Red、Green、Orange、Gold、Yellow、Lime、Cyan、GeekBlue、Purple、Pink、Magenta、Volcano、Grey),颜色值由PresetPrimaryColor.GetColor()统一获取。 - 自定义颜色(
Color):使用任意Color值作为 ToolTip 背景色。 - 默认颜色:由
ToolTipToken.ToolTipBackground控制(通常为深灰/黑色),文字为白色(ToolTipToken.ToolTipColor)。
设置 PresetColor 或 Color 后,背景色会覆盖默认 Token 值,文字色保持不变。
ToolTipService(内部服务)
ToolTipService 是 ToolTip 系统的核心引擎,负责监听全局输入事件并管理 ToolTip 的显示/隐藏生命周期:
| 职责 | 实现方式 |
|---|---|
| 监听鼠标移动 | 订阅 IInputManager.Process,处理 RawPointerEventArgs |
| 命中测试 | 沿可视树向上遍历,找到设置了 ToolTip.Tip 的最近控件 |
| 延迟显示 | 根据 ShowDelay 启动 DispatcherTimer |
| 快速切换 | 根据 BetweenShowDelay 判断是否跳过延迟直接显示 |
| 自动关闭 | 鼠标离开目标控件/窗口时关闭,鼠标按下时关闭 |
| 自定义控制 | IsCustomShowAndHide="True" 时跳过自动关闭逻辑 |
与 Ant Design 规范的对齐程度
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|---|---|---|---|
12 种方向 placement |
✅ | ✅ PlacementMode 枚举 |
✅ 完全对齐 |
箭头 arrow |
✅ true / false / { pointAtCenter } |
✅ IsShowArrow + IsPointAtCenter |
✅ 完全对齐 |
预设颜色 color |
✅ 预设名或自定义色 | ✅ PresetColor + Color |
✅ 完全对齐 |
延迟 mouseEnterDelay |
✅ 秒 | ✅ ShowDelay 毫秒 |
✅ 对齐(单位不同) |
连续延迟 mouseLeaveDelay |
✅ | ✅ BetweenShowDelay |
✅ 对齐 |
| 自定义内容 | ✅ ReactNode | ✅ Tip 接受任意 object |
✅ 对齐 |
受控模式 open |
✅ | ✅ IsOpen + IsCustomShowAndHide |
✅ 对齐 |
打开回调 onOpenChange |
✅ | ✅ ToolTipOpening / ToolTipClosing 事件 |
✅ 对齐 |
destroyTooltipOnHide |
✅ | ❌ Popup 复用 | ⚠️ 无需,Avalonia 自动管理生命周期 |
getPopupContainer |
✅ 指定挂载节点 | ❌ 不适用 | — 桌面端无 DOM 容器概念 |
overlayStyle / overlayClassName |
✅ | ❌ 通过 Style 选择器实现 | ✅ Avalonia 方式等效 |
zIndex |
✅ | ❌ 由 Popup 系统自动管理 | ✅ Avalonia 自动管理 |
fresh |
✅ 5.10.0+ 强制重新渲染 | ❌ 暂未支持 | ⚠️ 待评估 |
继承关系
Avalonia.Controls.Primitives.TemplatedControl
└── Avalonia.Controls.ContentControl
└── AtomUI.Desktop.Controls.ToolTip
├── implements IMotionAwareControl
├── implements IArrowAwareShadowMaskInfoProvider (internal)
└── implements IPopupHostProvider
注意:ToolTip 没有设备无关的基类(
AtomUI.Controls中无AbstractToolTip),因为 ToolTip 的交互行为(鼠标悬浮触发)本身具有桌面端特性。未来移动端可能采用长按触发等不同交互方式,因此两端实现可能差异较大,不适合抽取共享基类。
各层级职责划分:
| 层级 | 提供的能力 |
|---|---|
ContentControl |
任意内容容纳、Content / ContentTemplate、ContentPresenter 模板化呈现 |
AtomUI.Desktop.Controls.ToolTip |
Ant Design 视觉体系(箭头/方向/颜色)、附加属性接口、Design Token 集成、ToolTipService 交互服务、弹出动画、阴影效果 |
实现的接口:
| 接口 | 定义位置 | 作用 |
|---|---|---|
IMotionAwareControl |
AtomUI.Core |
支持 IsMotionEnabled 动画开关 |
IArrowAwareShadowMaskInfoProvider |
AtomUI.Controls(internal) |
为阴影渲染提供箭头感知的遮罩信息(圆角、边界、箭头位置) |
IPopupHostProvider |
Avalonia.Controls |
提供 Popup 宿主信息,用于弹出层管理 |
源码位置
| 层级 | 文件路径 | 说明 |
|---|---|---|
| 控件类 | src/AtomUI.Desktop.Controls/Tooltip/Tooltip.cs |
ToolTip 控件及附加属性 |
| 服务类 | src/AtomUI.Desktop.Controls/Tooltip/ToolTipService.cs |
ToolTip 交互服务(内部) |
| Token 定义 | src/AtomUI.Desktop.Controls/Tooltip/ToolTipToken.cs |
组件级 Design Token |
| 主题模板 | src/AtomUI.Desktop.Controls/Tooltip/Themes/ToolTipTheme.axaml |
ControlTheme AXAML |
| 主题常量 | src/AtomUI.Desktop.Controls/Tooltip/Themes/ToolTipThemeConstants.cs |
模板部件名称常量 |
| Gallery 示例 | controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TooltipShowCase.axaml |
使用范例 |
模板结构
ToolTip 的 ControlTemplate 结构简洁,以 ArrowDecoratedBox 为核心容器:
ArrowDecoratedBox (PART_ToolTipContainer) ← 箭头装饰盒子(承载背景、圆角、箭头绘制、阴影)
└── ContentPresenter (PART_ToolTipContentPresenter) ← 内容展示器(字符串自动转为 TextBlock)
设计特点:
- ArrowDecoratedBox:是 AtomUI 中专门用于箭头弹出组件的共享容器,在 ToolTip、Popover、Popconfirm 等组件中复用。它负责绘制三角箭头、管理内容区域圆角、计算箭头顶点位置。
- StringToTextBlockConverter:当
Content为字符串时,自动转换为带自动换行的TextBlock(TextWrapping="Wrap"),确保长文本正确显示。 - 背景色绑定:
ArrowDecoratedBox.Background通过TemplateBinding绑定到 ToolTip 的Background属性,当设置PresetColor或Color时,ToolTip 会更新Background,进而驱动ArrowDecoratedBox的背景和箭头颜色同步变化。
模板部件常量
| 常量名 | 值 | 说明 |
|---|---|---|
ToolTipThemeConstants.ToolTipContainerPart |
"PART_ToolTipContainer" |
箭头装饰盒子容器 |
ToolTipThemeConstants.ToolTipContainerPresenterPart |
"PART_ToolTipContentPresenter" |
内容展示器 |