- UI组件
- 桌面应用
【免费下载链接】SukiUI
UI Theme for AvaloniaUI
Loading是 SukiUI 内置的轻量级加载指示控件,用于在 AvaloniaUI 应用中展示正在进行的异步任务。本指南以官方文档 loading.md 为骨架,结合 Loading.cs 源码与 Demo 页面 ProgressView.axaml,完整讲解其 XAML 用法、Simple / Glow / Pellets 三种动画样式的差异,以及它基于 SkiaSharp(SKSL)着色器与 Composition CustomVisual 的底层渲染实现。读完本文,你将能够在自己的 SukiUI 项目中即插即用地配置加载动画,并理解其硬件/软件渲染的双路径机制。
控件一览
Loading是一个继承自Avalonia.Controls.Control的自绘控件(源码位于 Loading.cs),不依赖任何默认的 Avalonia 模板控件,而是通过组合层(Compositor)自定义视觉直接绘制。它在构造函数中默认将尺寸设置为50 × 50像素(Loading.cs),因此即使不做任何布局配置也能直接显示一个完整可用的加载动画。
快速上手:一行 XAML 引入
根据官方文档,最基本的用法只需在 XAML 中声明一个<suki:Loading />元素:
<suki:Loading />前提是当前视图已引入 SukiUI 命名空间:
<UserControl xmlns:suki="https://github.com/kikipoulet/SukiUI" ... > <suki:Loading /> </UserControl>若你的视图尚未合并 SukiUI 主题资源,请先在App.axaml中引入主题(详见 getting-started/installation)。
由于默认LoadingStyle为Simple、前景色自动取用主题的SukiPrimaryColor,这段最简单的代码即可得到一个跟随应用主题色的旋转加载动画。
三种动画样式:Simple、Glow、Pellets
控件通过LoadingStyle枚举属性切换动画外观,枚举定义于 Loading.cs:
| 枚举值 | 视觉特征 | 对应着色器 |
|---|---|---|
Simple | 细线圆环匀速旋转,尾部带轻微拖尾 | simple.sksl |
Glow | 线宽与光晕更大的发光圆环 | glow.sksl |
Pellets | 一段长弧带动多段短弧(颗粒)旋转的复合动画 | pellets.sksl |
官方 Demo 页面 ProgressView.axaml 中展示了三种样式的完整用法:
<StackPanel Spacing="15"> <suki:Loading LoadingStyle="Simple" /> <suki:Loading LoadingStyle="Glow" /> <suki:Loading LoadingStyle="Pellets" /> </StackPanel>从源码实现看,LoadingStyleProperty注册时带有值校验约束(Loading.cs):传入的枚举值若未在LoadingStyle中定义,会被强制回退为Simple,因此非法赋值不会导致崩溃。样式切换会在OnPropertyChanged中即时生效——控件直接把对应样式的新SukiEffect实例通过消息发送给渲染处理器(Loading.cs),无需重建视觉树。
三种样式的着色器差异
三种样式均使用 SKSL(Skia 着色器语言)编写,其源码位于 SukiUI/Content/Shaders/Loading/,核心逻辑大致相同:以iResolution归一化坐标、用atan(uv.y, uv.x)计算极角、再乘以iTime驱动的fallOff系数形成旋转拖尾。
Simple:radius = 0.3,线宽lineWidth = 1像素,光晕glowSize = 1像素(内部再放大 2 倍),是一条宽度恒定、带轻微辉光的旋转圆弧;Glow:线宽提升到2像素、光晕放大到3像素,并将光晕随fallOff渐变,视觉上发光感明显更强;Pellets:通过有符号距离场(SDF)绘制“最长弧 + 多段短弧”,每帧按floor(T)分段旋转,形成颗粒追逐长弧的效果,线宽由widthReduction = 0.02控制。
三者均通过uniform vec3 iForeground接收前景色,输出时与iAlpha相乘(return vec4(color) * vec4(iForeground, iAlpha);),从而保持半透明与主题色一致。
外观控制:Foreground 与尺寸
Loading对外暴露两个核心属性:
Foreground(前景色)
类型为IBrush。源码中有两个值得注意的行为:
- 默认自动取主题主色:当
Foreground为null时,控件通过动态资源绑定SukiPrimaryColor(Loading.cs),因此换主题时加载动画颜色会自动跟随; - 运行时更改即时刷新:
ForegroundProperty变化时,控件将新颜色转换为float[3]数组通过SendHandlerMessage推送给渲染处理器(Loading.cs),无需重新挂载。
显式指定示例:
<suki:Loading LoadingStyle="Glow" Foreground="ForestGreen" />尺寸
控件默认50 × 50,可通过标准布局属性覆盖:
<suki:Loading LoadingStyle="Pellets" Width="80" Height="80" />注意:渲染尺寸跟随BoundsProperty变化,控件在OnPropertyChanged中检测到尺寸变化后会把新尺寸同步给自定义视觉(Loading.cs),所以缩放动画或容器尺寸变化时动画不会失真。
源码级原理:Composition CustomVisual + SKSL 渲染管线
Loading的高性能动画得益于 Avalonia 的ElementComposition组合层。其完整生命周期如下:
- 挂载(
OnAttachedToVisualTree):通过ElementComposition.GetElementVisual(this).Compositor创建CompositionCustomVisual,注册LoadingEffectDraw处理器,并通过SetElementChildVisual挂到控件上(Loading.cs); - 启动动画:发送
EffectDrawBase.StartAnimations消息,渲染处理器内部的Stopwatch开始计时(EffectDrawBase.cs),此后每帧通过OnAnimationFrameUpdate触发重绘并注册下一帧(EffectDrawBase.cs); - 传递参数:依次发送前景色
float[3]与当前样式的SukiEffect(Loading.cs); - 渲染:
LoadingEffectDraw.Render使用EffectWithCustomUniforms注入iForeground后生成SKShader,以单次DrawRect铺满整个控件区域(Loading.cs); - 卸载(
OnDetachedFromVisualTree):发送StopAnimations并清理自定义视觉引用(Loading.cs)。
SukiEffect 着色器加载与 uniform 注入
SukiEffect(SukiEffect.cs)负责把.sksl文件编译为SKRuntimeEffect:
FromEmbeddedResource("simple")会在程序集中按名称查找嵌入资源并预编译,任何编译错误都会以ShaderCompilationException抛出(SukiEffect.cs);FromString会自动在所有着色器头部注入iTime、iDark、iAlpha、iResolution、iPrimary、iAccent、iBase等基础 uniform(SukiEffect.cs),因此 shader 源码中只需声明自己用到的自定义 uniform(如iForeground)。
需要留意的是:要让FromEmbeddedResource能找到着色器文件,.sksl文件必须在 csproj 中标记为嵌入资源(见 SukiEffect.cs 的注释说明)。Loading 所用三个着色器即位于 Content/Shaders/Loading/ 目录下。
硬件加速与软件渲染双路径
EffectDrawBase.OnRender会根据渲染环境自动选择路径(EffectDrawBase.cs):
- 硬件加速路径:
GrContext非空时调用Render,即上文描述的 SKSL 着色器绘制; - 软件回退路径:无 GPU 或强制软件渲染时调用
RenderSoftware。LoadingEffectDraw.RenderSoftware用DrawArc直接绘制一条按AnimationSeconds * 360f旋转的圆角描边圆弧(Loading.cs),保证在没有硬件加速的环境(如某些设计器预览场景)下依然可见。
源码注释(Loading.cs)明确提醒:软件渲染路径目前可能在设计器预览器中存在兼容性问题,作者建议后续可退化为简单圆形绘制——这意味着如果发现设计器预览不理想,可优先在运行时(Run 模式)验证效果。
结合 BusyArea:让 Loading 覆盖任意内容
Loading不仅是独立控件,还被 SukiUI 的忙碌遮罩能力内部复用。在 LoadingBehavior.cs 中,ShowBusy会动态创建一个40 × 40的Loading实例放入Popup,并将其锚定到目标控件上形成遮罩覆盖层:
var loading = new Loading { Width = 40, Height = 40, Opacity = 0 };对应的 XAML 用法是配合 BusyArea.axaml 或直接在任意控件上附加IsBusy属性。例如在数据加载期间锁住按钮/面板:
<StackPanel suki:LoadingBehavior.IsBusy="{Binding IsLoading}" suki:LoadingBehavior.DimOpacity="0.3"> <!-- 业务内容 --> </StackPanel>IsBusy为true时目标内容透明度动画至DimOpacity(默认0.3)并禁用命中测试,同时弹出居中的Loading动画;为false时再平滑还原(LoadingBehavior.cs)。它还会跟随宿主ScrollViewer的滚动事件重新居中弹层,保证滚动后加载指示不会错位(LoadingBehavior.cs)。这套机制在官方 Demo 的 BusyArea 示例(BusyArea.axaml.cs)中有完整演示。
常见问题与使用建议
- 着色器找不到/编译失败:确认使用的
.sksl文件已作为嵌入资源编译进程序集;自定义 shader 建议走SukiEffect.FromString并复用其自动注入的 uniform 体系。 - 设计器预览异常:预览器通常无硬件加速,
Loading将走软件回退的DrawArc路径;若预览效果与运行时不一致,以运行态为准。 - 颜色不跟随主题:请勿在未设置
Foreground时手动重置该属性为null之外的值;如需固定颜色直接赋值即可,控件会即时重绘。 - 尺寸适配:在
Grid拉伸布局中使用时,建议显式指定Width/Height,避免被拉伸为不规则矩形影响圆弧比例。
进一步阅读
- 官方文档:loading.md
- 控件实现:SukiUI/Controls/Loading.cs
- Demo 页面:SukiUI.Demo/Features/ControlsLibrary/ProgressView.axaml
- 着色器源码:SukiUI/Content/Shaders/Loading/
- 渲染基类:SukiUI/Utilities/Effects/EffectDrawBase.cs
- 着色器工具类:SukiUI/Utilities/Effects/SukiEffect.cs
- 忙碌遮罩行为:SukiUI/Animations/LoadingBehavior.cs
- UI组件
- 桌面应用
【免费下载链接】SukiUI
UI Theme for AvaloniaUI
相关推荐
daisyUI Loading 组件完全指南:6 种加载动画、5 档尺寸与源码级原理解析
daisyUI Loading 组件完全指南:6 种加载动画、5 档尺寸与源码级原理解析 Loading(加载)组件是 daisyUI 提供的一组纯 CSS 加
前端UI组件SkSL 着色语言完全指南:Skia 内部着色语言的设计差异与同步原语解析
SkSL 着色语言完全指南:Skia 内部着色语言的设计差异与同步原语解析 导读 SkSL(Skia Shading Language)是 Skia 以 GLS
图形学IBAnimatable 加载动画(Activity Indicator)完全指南:Interface Builder 与代码中的 40 种 Loading 动画
IBAnimatable 加载动画(Activity Indicator)完全指南:Interface Builder 与代码中的 40 种 Loading 动
移动开发UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考