Files
AtomUI/docs/Core/IconSystem.md
T
chinboy 2a9620a3f9 docs(Core): add and update core subsystem documentation
- Add IconSystem, AnimationSystem, CollectionSystem documentation
- Add ControlInfrastructure, CoreTypesAndUtilities documentation
- Add DataBindingSystem, MediaAndDrawing documentation
- Update MotionScene docs (Architecture, BuiltinMotions, DeveloperGuide, Overview)
- Update commit-message-convention: Body section Optional → Recommended
2026-04-10 18:48:42 +08:00

14 KiB
Raw Blame History

AtomUI Icon 系统

本文档描述 AtomUI.Core 中 Icon 子系统的架构设计,包括矢量图标抽象基类、泛型 XAML 标记扩展、Expression Tree 缓存优化、绘制指令体系及旋转动画支持。


1. 概述

AtomUI Icon 系统提供了一套可扩展的矢量图标框架,支持多主题类型、自定义笔触/填充、旋转动画(Spin/Pulse),并通过 Expression Tree 编译缓存优化图标实例创建性能。该系统主要服务于 AtomUI.Icons.AntDesign(自动生成的 Ant Design 图标集),但架构上允许任何图标集接入。

源文件清单

文件 职责
Controls/Icon/Icon.cs 图标抽象基类,继承 PathIcon,定义所有公共属性与自定义渲染
Controls/Icon/IconProvider.cs 泛型 XAML 标记扩展 IconProvider<TIconKind>,在 XAML 中创建图标实例
Controls/Icon/IconProviderCache.cs 线程安全的 Expression Tree 编译缓存
Controls/Icon/DrawingInstruction.cs 绘制指令抽象基类及 7 种具体指令
Controls/Icon/Common.cs 枚举定义:IconAnimation、IconThemeType、IconBrushType
Controls/Icon/PulseEasing.cs 步进式脉冲缓动曲线

2. 架构总览

┌──────────────────────────────────────────────────────────────┐
│  XAML 使用层                                                  │
│  <antdicons:LoadingOutlined Animation="Spin" />              │
│  <antdicons:CheckCircleFilled FillBrush="{...}" />           │
│                              │                                │
│                     MarkupExtension.ProvideValue()            │
│                              │                                │
│  ┌───────────────────────────▼──────────────────────────┐    │
│  │  IconProvider<TIconKind>  (MarkupExtension)           │    │
│  │  - Kind → 枚举值(如 AntDesignIconKind.Loading)       │    │
│  │  - StrokeBrush / FillBrush / Width / Height           │    │
│  │  - GetTypeForKind(kind) → 具体 Icon 类型               │    │
│  │  - CreateFactory(type)  → Expression.Lambda 编译工厂   │    │
│  └───────────────────────────┬──────────────────────────┘    │
│                              │                                │
│  ┌───────────────────────────▼──────────────────────────┐    │
│  │  IconProviderCache  (static, ConcurrentDictionary)    │    │
│  │  - TypeCache:    Enum → EnumValue → Type              │    │
│  │  - CreatorCache:  Enum → EnumValue → Func<Icon>       │    │
│  │  - TypeToCreator: Type → Func<Icon>                   │    │
│  │  → Expression Tree 编译后的无参构造函数委托             │    │
│  └───────────────────────────┬──────────────────────────┘    │
│                              │ creator()                      │
│  ┌───────────────────────────▼──────────────────────────┐    │
│  │  Icon  (abstract, extends PathIcon)                    │    │
│  │  - DrawingInstructions → IList<DrawingInstruction>     │    │
│  │  - DrawBrushes[5] / DrawPens[5]  (笔触/画笔数组)     │    │
│  │  - Render() → 自定义矢量渲染                           │    │
│  │  - SetupRotateAnimation() → Spin/Pulse 旋转动画       │    │
│  │  - ConfigureTransitions() → 颜色过渡动画               │    │
│  │  implements ICustomHitTest, IMotionAwareControl         │    │
│  └──────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────┘

3. Icon 抽象基类

3.1 继承关系

Avalonia.Controls.PathIcon
    └── AtomUI.Controls.Icon (abstract)
            ├── implements ICustomHitTest
            └── implements IMotionAwareControl

Icon 继承自 Avalonia 的 PathIcon,但完全重写了渲染逻辑 — 不使用 PathIcon 的 Data 属性,而是通过 DrawingInstructions 绘制指令体系进行自定义渲染。

3.2 公共属性

属性 类型 默认值 说明
StrokeBrush IBrush? null 主笔触颜色
FillBrush IBrush? null 主填充颜色
SecondaryStrokeBrush IBrush? null 副笔触颜色(双色图标)
SecondaryFillBrush IBrush? null 副填充颜色(双色图标)
FallbackBrush IBrush? White 备选颜色
IconTheme IconThemeType Filled 图标主题类型
StrokeWidth double 4 笔触宽度
StrokeLineCap PenLineCap Round 线端样式
StrokeLineJoin PenLineJoin Round 连接样式
LoadingAnimation IconAnimation None 旋转动画类型
LoadingAnimationDuration TimeSpan 1s 旋转动画周期
FillAnimationDuration TimeSpan 200ms 颜色过渡时长
IsMotionEnabled bool — 动画开关(绑定全局 Token)

3.3 笔刷类型体系

Icon 内部维护了一个 5 元素的笔刷数组(DrawBrushes[5])和对应的画笔数组(DrawPens[5]),索引由 IconBrushType 枚举决定:

public enum IconBrushType
{
    Stroke,           // [0] 主笔触
    Fill,             // [1] 主填充
    SecondaryStroke,   // [2] 副笔触
    SecondaryFill,     // [3] 副填充
    Fallback,          // [4] 备选
    None               // 无笔刷
}

绘制指令通过 StrokeBrush 和 FillBrush 字段引用枚举值,在渲染时调用 Icon.FindIconBrush(brushType) 从数组中查找实际笔刷。这种间接引用设计允许:

  • 多个绘制指令共享同一笔刷实例
  • 笔刷变化时自动影响所有引用该类型的指令
  • 支持 BindingPriority.Animation 优先级的颜色过渡

3.4 自定义渲染流程

Icon.Render(DrawingContext)
│
├── 1. FillRectangle(Background) — 绘制背景
├── 2. 计算 ViewBox → DesiredSize 的缩放比 scale
├── 3. CalculateGlobalGeometryMatrix() — 获取全局变换矩阵
├── 4. PushTransform(scale) — 应用缩放
└── 5. foreach instruction in DrawingInstructions:
        └── instruction.Draw(context, globalMatrix, this)
            ├── BuildGeometry() — 延迟构建几何体(缓存)
            ├── FindIconBrush() — 从 Icon 查找笔刷
            ├── BuildPen() — 构建画笔
            ├── 应用 Transform + globalMatrix
            └── DrawGeometry(fillBrush, pen, geometry)

3.5 旋转动画

Icon 支持两种旋转动画模式,通过 LoadingAnimation 属性控制:

模式 效果 缓动 适用场景
Spin 匀速连续旋转 0°→360° 线性(默认) Loading 图标
Pulse 步进式旋转(8 步) PulseEasing(阶梯函数) 脉冲加载效果

动画通过 Style.Animations 机制实现:

var animation = new Animation {
    Duration = LoadingAnimationDuration,
    IterationCount = IterationCount.Infinite,
    FillMode = FillMode.Backward,
    Children = {
        new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(AngleAnimationRotateProperty, 0d) } },
        new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(AngleAnimationRotateProperty, 360d) } }
    }
};
if (LoadingAnimation == IconAnimation.Pulse) {
    animation.Easing = new PulseEasing();  // 8 步阶梯函数
}

PulseEasing 将连续的 0→1 进度映射为 8 个离散步进值(0, 0.125, 0.25, ...),产生"卡顿旋转"的视觉效果。

3.6 颜色过渡

当 IsMotionEnabled = true 时,Icon 自动为 5 种笔刷属性添加 SolidColorBrushTransition:

Transitions = [
    BaseTransitionUtils.CreateTransition<SolidColorBrushTransition>(StrokeBrushProperty, FillAnimationDuration),
    BaseTransitionUtils.CreateTransition<SolidColorBrushTransition>(FillBrushProperty, FillAnimationDuration),
    BaseTransitionUtils.CreateTransition<SolidColorBrushTransition>(SecondaryFillBrushProperty, FillAnimationDuration),
    BaseTransitionUtils.CreateTransition<SolidColorBrushTransition>(SecondaryStrokeBrushProperty, FillAnimationDuration),
    BaseTransitionUtils.CreateTransition<SolidColorBrushTransition>(FallbackBrushProperty, FillAnimationDuration),
];

这使得图标在颜色变化时(如 hover 状态)有平滑的颜色过渡效果。


4. IconProvider — 泛型标记扩展

4.1 设计

IconProvider<TIconKind> 是一个 MarkupExtension,允许在 XAML 中通过枚举值创建图标实例:

<antdicons:LoadingOutlined />                       <!-- Kind 自动匹配 -->
<antdicons:CheckCircleFilled FillBrush="Green" />   <!-- 自定义笔刷 -->

泛型参数 TIconKind 是图标集的枚举类型(如 AntDesignIconKind),由 AtomUI.Icons.AntDesign.Generator 自动生成。

4.2 实例创建流程

IconProvider.ProvideValue(serviceProvider)
│
├── 1. GetIcon(Kind)
│      ├── GetTypeForKind(kind) → 具体 Icon 子类的 Type
│      ├── IconProviderCache.GetOrAddCreator(enumType, kind, ...)
│      │      └── CreateFactory(type) → Expression.Lambda<Func<Icon>>.Compile()
│      └── creator() → new XxxIcon()
│
├── 2. 设置可选属性
│      ├── Animation → LoadingAnimationProperty
│      ├── StrokeBrush / FillBrush / SecondaryStroke / SecondaryFill
│      └── Width / Height
│
└── 3. return icon

4.3 Expression Tree 缓存优化

每个图标类型的无参构造函数被编译为一个 Func<Icon> 委托并缓存,避免反复反射调用:

protected virtual Func<Icon> CreateFactory(Type type)
{
    var constructor = type.GetConstructor(Type.EmptyTypes);
    var newExpr = Expression.New(constructor);
    var lambda = Expression.Lambda<Func<Icon>>(newExpr);
    return lambda.Compile();  // 编译为原生委托
}

IconProviderCache 使用三层 ConcurrentDictionary 缓存:

TypeCache:     Enum类型 → { 枚举值 → Type }           // Kind → 具体图标类型
CreatorCache:  Enum类型 → { 枚举值 → Func<Icon> }      // Kind → 编译后工厂
TypeToCreator: Type → Func<Icon>                        // 类型 → 工厂(跨枚举共享)

这确保了每个图标类型的构造函数只被编译一次,后续调用直接使用缓存的委托,性能接近直接 new。


5. DrawingInstruction — 绘制指令体系

5.1 指令继承体系

DrawingInstruction (abstract)
├── RectDrawingInstruction       — 矩形(支持圆角)
├── CircleDrawingInstruction     — 圆形
├── EllipseDrawingInstruction    — 椭圆
├── LineDrawingInstruction       — 直线
├── PolylineDrawingInstruction   — 折线
├── PolygonDrawingInstruction    — 多边形
└── PathDrawingInstruction       — SVG 路径

5.2 指令基类属性

属性 类型 说明
Transform Matrix? 指令级变换矩阵
Opacity double 指令级不透明度
StrokeBrush IconBrushType? 笔触类型引用
FillBrush IconBrushType? 填充类型引用
IsStrokeEnabled bool 是否启用笔触
IsStrokeWidthCustomizable bool 笔触宽度是否跟随 Icon 设置
IsStrokeLinejoinCustomizable bool 连接样式是否跟随
IsStrokeLinecapCustomizable bool 端点样式是否跟随

5.3 延迟构建与缓存

每个 DrawingInstruction 在首次 Draw() 调用时通过 BuildGeometry() 构建 Geometry 对象并缓存。后续渲染复用缓存的 Geometry,仅更新 Transform 和 Brush:

public void Draw(DrawingContext drawingContext, in Matrix globalGeometryMatrix, Icon icon)
{
    _geometry ??= BuildGeometry();  // 延迟构建 + 缓存
    // ... 应用变换、获取笔刷、绘制
}

6. 图标主题类型

public enum IconThemeType
{
    Filled,      // 实心填充
    Outlined,    // 描边
    Rounded,     // 圆角
    Sharp,       // 尖角
    TwoTone,     // 双色
    MultiColor   // 多色
}

当 IconTheme 为 Filled、Outlined、Rounded、Sharp 时,Icon 标记为 IsSupportSimpleTransition = true,允许简化的颜色过渡。TwoTone 和 MultiColor 类型使用多个笔刷通道,过渡逻辑更复杂。


7. 与 AtomUI.Icons.AntDesign 的关系

AtomUI.Icons.AntDesign 项目由 AtomUI.Icons.AntDesign.Generator 源代码生成器自动生成。生成器读取 Ant Design 图标的 SVG 数据,为每个图标生成:

  1. 一个继承 Icon 的具体类(如 LoadingOutlinedIcon)
  2. DrawingInstructions 列表中的绘制指令
  3. IconProvider<AntDesignIconKind> 的具体实现

Icon 系统本身不依赖任何具体图标集 — 它只提供框架。具体图标集通过实现 Icon 子类和 IconProvider<T> 接入。