实现 Windows 中的“转圈圈”加载动画效果
概述
相信大家在电脑上基本都见过这样一个动画吧:
自 Windows 8 起,Windows 的开机、Metro/UWP 应用的加载都使用了我们非常熟悉那个“转圈圈”动画。老实说,这个动画与当初 Windows 8 的极致扁平化配合得很好,流畅而不失优雅。但实际上,它的实现并非采用了我们 Web 开发中常用的贴图,而是使用了字体来进行实现——将特殊字体家族中的某些字体轮番播放,利用视觉暂留现象,制造出一种“这个动画是连续”的假象。
实际上,这是非常科学且实用的,因为字符和图像所包含的数据量完全不是一个量级的,以一张 $ 128×128 $ 的彩色 GIF 动图来说,这是一个 128 px 的方阵,每个元素又包含三个通道(RGB),每个通道都是一个 char
类型的值,即一个字节,假设一秒播放 24 fps,那么一秒内的数据量就是 $ 3×128×128×24 $,即 1179648 字节(1.125 MB),这可比一个字符的开销大的太多了。
因此,我们就已经明确了:实现它就是使用特定的字符,然后通过编程的方式进行轮番显示,让它“动起来”。本文将使用 C#
作为编程语言,使用 Avalonia UI 作为 GUI 框架,使用 Segoe UI Semilight 字体家族进行实际的应用。
Segoe UI Semilight字体家族
打开 Windows 字符映射表,找到 Segoe UI Semilight,我们一直找,发现并没有具有“Windows 加载动画字体”特征的字符出现:
实际上,这份字符表是“被动了手脚的”,我们可以发现,字符编码从上图中的 U+AB65
跳到了 U+FB00
,中间的那么多字符都不见了:
因此,需要我们从网上下载一个字体,名叫 Segoe Boot Semilight。一般来说,如果下载正确,那么在资源管理器中会看到这么一个 .ttf
格式的字体文件:
执行安装,这个时候再打开字符映射表,就找到 Segoe Boot Semilight 字体了。往下翻翻,就找到了我们需要的东西了:
所以,我们就可以从 Segoe Boot Semilight 字体家族中 U+E052
开始,轮番显示字体来实现 Windows 加载动画了
吗?
实际上,这里有一个问题:字体是字体,字体家族是字体家族,两者并不完全一一对应。前文中,我们发现 Segoe UI Semilight 缺了一些字体,而观察到以 U+E052
起始的一段字符序列似乎就在缺失的那一部分中,我们可以合理推理:Segoe Boot Semilight 字体中的这些字符实际上属于 Segoe UI Semilight 字体家族。
为了验证这一推理,我们打开“字符大全集”,该应用可由 Microsoft Store 下载安装:
我们搜索这个字符,果真在 Segoe UI Semilight 中发现了它:
从右边栏的下方我们可以看到,该软件已经贴心地给出了这个字符号在 XAML
和 HTML
中的引用方法,显然,我们要使用 Segoe UI Semilight 字体家族:
在 Avalonia UI 中构建一个简易的动画效果应用
碍于篇幅原因,本文不予叙述如何安装 Avalonia Templates。我们打开 Visual Studio,创建一个 Avalonia .NET App:
在 MainWindow.axaml
中,修改 XAML
代码:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
x:Class="Loading_Animation.MainWindow"
Title="Loading_Animation">
<Grid>
<Label x:Name="loadingLabel"
<!-- 使用 Segoe UI Semilight -->
FontFamily="Segoe UI Semilight"
FontSize="100"
<!-- 从 U+E052 开始 -->
Content=""
HorizontalAlignment="Center"
VerticalAlignment="Center">
</Label>
</Grid>
</Window>
接着,在 MainWindow.axaml.cs
中,修改 C#
代码:
using System;
using Avalonia.Controls;
using Avalonia.Threading; //使用 DispatcherTimer 类
namespace Loading_Animation
{
public partial class MainWindow : Window
{
// 定义计时器
private readonly DispatcherTimer _timer;
private int _currentFrame;
private const int StartCodePoint = 0xE052;
private const int EndCodePoint = 0xE0C6;
private const int FrameCount = EndCodePoint - StartCodePoint + 1;
public MainWindow()
{
_currentFrame = 0;
// 初始化 DispatcherTimer
_timer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(30) // 计时器时间间隔
};
_timer.Tick += Timer_Tick;
_timer.Start();
InitializeComponent();
}
private void Timer_Tick(object? sender, EventArgs e)
{
// 计算当前帧的 Unicode 码位
int codePoint = StartCodePoint + _currentFrame;
// 将Unicode码位转换为字符串并更新 Label 的 Content
loadingLabel.Content = char.ConvertFromUtf32(codePoint);
// 更新帧索引,循环播放
_currentFrame = (_currentFrame + 1) % FrameCount;
}
// 使用复写的 OnClosed 方法,确保窗口关闭时计时器停止
protected override void OnClosed(EventArgs e)
{
_timer.Stop();
base.OnClosed(e);
}
}
}
非常轻松地,我们就能获取到一个有 Windows 加载动画效果的程序了:
大功告成,未来,可以把这个动画用 Label
或者 TextBlock
封装成一个函数或类,或者拓展一下 WPF/Avalonia 中的动画,就可以在许多地方用上这个加载动画,以增强应用与用户之间的交互性。
总结
通过探究我们发现,Windows 中的加载动画实际上并不是 GIF 动画贴图,而是使用 Segoe UI Semilight 字体家族的 Segoe Boot Semilight 字体中的部分字符轮番显示进行实现的。我们使用 Avalonia UI 构建了一个简单的应用程序,使用 Avalonia.Threading
命名空间中的 DispatcherTimer
类作为计数器,对 U+E052
到 U+E0C6
进行轮番播放,在 Label
控件中实现了这个动画效果。若有其他关于 Windows 加载动画的相关知识,欢迎各位在下方评论区补充留言!