☰
SukiUI Loading 加载控件完全指南:三种动画样式与 SKSL 着色器渲染原理
2026/10/5 10:21:56 网站建设 项目流程
  • UI组件
  • 桌面应用

【免费下载链接】SukiUI

UI Theme for AvaloniaUI

项目地址:https://gitcode.com/gh_mirrors/su/SukiUI
点击查看免费下载

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。源码中有两个值得注意的行为:

  1. 默认自动取主题主色:当Foreground为null时,控件通过动态资源绑定SukiPrimaryColor(Loading.cs),因此换主题时加载动画颜色会自动跟随;
  2. 运行时更改即时刷新: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组合层。其完整生命周期如下:

  1. 挂载(OnAttachedToVisualTree):通过ElementComposition.GetElementVisual(this).Compositor创建CompositionCustomVisual,注册LoadingEffectDraw处理器,并通过SetElementChildVisual挂到控件上(Loading.cs);
  2. 启动动画:发送EffectDrawBase.StartAnimations消息,渲染处理器内部的Stopwatch开始计时(EffectDrawBase.cs),此后每帧通过OnAnimationFrameUpdate触发重绘并注册下一帧(EffectDrawBase.cs);
  3. 传递参数:依次发送前景色float[3]与当前样式的SukiEffect(Loading.cs);
  4. 渲染:LoadingEffectDraw.Render使用EffectWithCustomUniforms注入iForeground后生成SKShader,以单次DrawRect铺满整个控件区域(Loading.cs);
  5. 卸载(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

项目地址:https://gitcode.com/gh_mirrors/su/SukiUI
点击查看免费下载
上一篇:OkHttp Coroutines 协程扩展库实战:用 executeAsync 优雅整合 Kotlin 挂起函数
下一篇:Civitai 付费模型加载覆盖度审计:从 CoveredCheckpoint 到三分支覆盖模型

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询