WPF动态加载动画

<Grid x:Name="loadingMask" Background="#66000000" Visibility="Visible"> <Ellipse Width="40" Height="40" Stroke="White" StrokeThickness="4" StrokeDashArray="2,6" RenderTransformOrigin="0.5,0.5"> <Ellipse.RenderTransform> <RotateTransform/> </Ellipse.RenderTransform> <Ellipse.Triggers> <EventTrigger RoutedEvent="Loaded"> <BeginStoryboard> <Storyboard RepeatBehavior="Forever"> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" From="0" To="360" Duration="0:0:1" /> </Storyboard> </BeginStoryboard> </EventTrigger> </Ellipse.Triggers> </Ellipse> </Grid>

很好,这段 XAML 看起来不长,但几乎把 WPF 动画、变换、触发器的精髓都用上了
我按 “从外到内、从静态到动态、从 UI 到底层机制” 给你逐行拆解,并补充一些只有做过产品的人才会注意的点


一、整体在干什么(一句话版)

这是一个“加载遮罩层”,中间有一个会不停旋转的圆环,用来表示“正在加载中”

  • Grid:遮罩层(挡住下面的 WebView)
  • Ellipse:画一个圆
  • StrokeDashArray:把圆变成“虚线环”
  • RotateTransform + DoubleAnimation:让它不停旋转

二、最外层:遮罩 Grid

<Grid x:Name="loadingMask"
      Background="#66000000"
      Visibility="Visible">

1️⃣ 为什么用 Grid?

  • Grid 是最常用的 Overlay 容器

  • 可以:

    • 盖住下面的控件(WebView)
    • 居中放 Loading

2️⃣ Background="#66000000" 是什么意思?

这是 ARGB 十六进制颜色

#66 00 00 00
 ↑  ↑  ↑  ↑
 α  R  G  B
  • 66 = 十六进制 ≈ 40% 透明
  • 000000 = 黑色

👉 半透明黑色遮罩

  • 能让用户知道:内容还在
  • 又明确“当前不可操作”

📌 工业级 UI 常用透明度:#55000000 ~ #88000000


3️⃣ Visibility="Visible"

  • 默认显示
  • 实际项目中通常由代码控制:
loadingMask.Visibility = Visibility.Collapsed;

三、核心元素:Ellipse(为什么不用 Image)

<Ellipse Width="40" Height="40"
         Stroke="White"
         StrokeThickness="4"
         StrokeDashArray="2,6"
         RenderTransformOrigin="0.5,0.5">

1️⃣ Ellipse 是“只有边框的圆”

  • Width = Height → 正圆
  • 没有 Fill → 中间是透明的
  • 只画边框(Stroke

2️⃣ Stroke="White"

  • 白色边框
  • 在深色遮罩上对比明显

3️⃣ StrokeThickness="4"

  • 圆环“粗细”
  • 数值越大,看起来越稳重

📌 产品经验:

  • 32~40 px → 小 Loading
  • 4~6 px → 合适

4️⃣ ⭐ StrokeDashArray="2,6"(重点)

这是 把实线变成虚线的关键

2 = 实线长度
6 = 空白长度

效果:

██      ██      ██      ██

👉 如果你不用这个,转起来看不出旋转

常见对比

DashArray 效果
完整圆,看不出转
1,3 细碎
2,6 非常常用
4,2 像齿轮

5️⃣ ⭐ RenderTransformOrigin="0.5,0.5"

这是旋转是否“像人”的关键属性。

(0,0)   左上角
(0.5,0.5) 正中心
(1,1)   右下角

👉 不写这个:

  • 默认 (0,0)
  • 圆会 绕左上角飞着转

✔️ (0.5,0.5) = 绕中心旋转


四、旋转核心:RenderTransform

<Ellipse.RenderTransform>
    <RotateTransform/>
</Ellipse.RenderTransform>

这一步只做一件事:

告诉 WPF:这个控件可以被“旋转”

  • 并没有指定角度
  • 初始角度 = 0°

后面动画会去改它的 Angle


五、动画系统(重点中的重点)

<Ellipse.Triggers>

WPF 有三种动画入口:

  • EventTrigger(事件)
  • Style Trigger
  • VisualStateManager

这里用的是 最简单稳定的 EventTrigger


1️⃣ RoutedEvent="Loaded"

<EventTrigger RoutedEvent="Loaded">

意思是:

当 Ellipse 加载到视觉树中时

✔️ 只触发一次
✔️ 非常适合 Loading 动画


2️⃣ BeginStoryboard

<BeginStoryboard>

Storyboard = 动画容器


3️⃣ Storyboard 本体

<Storyboard RepeatBehavior="Forever">
  • RepeatBehavior="Forever"
  • 👉 无限循环
  • 如果不写,只转一圈就停

4️⃣ 核心动画:DoubleAnimation

<DoubleAnimation
    Storyboard.TargetProperty="RenderTransform.Angle"
    From="0"
    To="360"
    Duration="0:0:1"
/>

逐项解释:

🔹 TargetProperty

RenderTransform.Angle

意思是:

改的是 RotateTransform 的 Angle 属性

📌 如果你写错:

  • 不报错
  • 但不会动(WPF 的经典坑)

🔹 From / To

0 → 360
  • 转一整圈
  • 单位:度(°)

🔹 Duration

0:0:1 = 1 秒
时间 观感
0.5s 很快
1s 标准
1.5s 稳重

六、整个动画链路(流程图)

Ellipse Loaded
     ↓
BeginStoryboard
     ↓
DoubleAnimation
     ↓
修改 RotateTransform.Angle
     ↓
不断从 0 → 360
     ↓
Repeat Forever

七、为什么这是“工业级写法”

✔️ 不需要 code-behind
✔️ GPU 级别渲染
✔️ 无 Timer
✔️ 性能极好
✔️ 样式可复用


八、你可以怎么改(进阶)

▶ 改颜色

Stroke="#00FFAA"

▶ 改速度

Duration="0:0:0.8"

▶ 做成组件

<local:LoadingSpinner/>

▶ 和 WebView 联动

loadingMask.Visibility =
    webView.CoreWebView2 != null ? Visibility.Collapsed : Visibility.Visible;

posted @ 2025-12-24 11:04  JohnYang819  阅读(3)  评论(0)    收藏  举报