「眨眼」UI 特效 - 在 Winform/WPF/WinUI3/Avalonia/Web 的实现
2026/7/13 2:44:50 网站建设 项目流程

目录

1,动画原理

2,动画拆解

2.1. 动画1 — 眼睑遮罩

2.1. 动画2 — 双层模糊换图

2.1. 动画3 — 整体缩放

2.1. 动画合并

3,五种UI框架 实现

3.1. WPF 实现

技术栈要点

关键代码:遮罩结构(XAML)

关键代码:动画1 驱动

✅ 优势

⚠️ 劣势 / 坑

3.2. Web实现

技术栈要点

关键代码:遮罩路径 + SVG 模糊

关键代码:动画1 每帧刷新

✅ 优势

⚠️ 劣势

3.3. Avalonia 实现

关键代码:遮罩每帧重建 Geometry

平台补偿

✅ 优势

⚠️ 劣势 / 周折

3.4. WinUI 3 实现

关键代码:Win2D 遮罩(替代 Path.BlurEffect)

关键代码:图片模糊 workaround

关键代码:Storyboard 动画 RadiusY

✅ 优势

⚠️ 劣势

3.5. WinForms 实现

关键代码:单帧合成

✅ 优势

⚠️ 劣势

4,五种UI框架 对比

差异:同一效果用不同技术

5,总结

5.1 遮罩:形状与模糊的先后顺序

5.2 动画2:图层时序 > 动画曲线

5.3 平台常量:共享语义 vs 共享数值

5.4 框架能力边界清单

6. 源码下载


这么可爱的【眨眼】转场动画如何实现呢?


1,动画原理

我们可以理解为三层叠加

这里的遮罩不是「画一条线」,而是矩形减去椭圆(WPFCombinedGeometry.Exclude, SVGfill-rule="evenodd"),再对整个形状做静态高斯模糊(Radius ≈ 30), 使眼睑边缘与人像产生柔和过渡。动画过程中只改变椭圆的RadiusY(270 → 10 → 270)。

// 共享参数 BlinkConstants(节选) ViewportWidth = 400, ViewportHeight = 600 EllipseCenter = (200, 300), EllipseRadiusX = 500 BlinkRadiusY: Open → Closed → Open // 各平台 Open 值略有平台补偿 MaskBlur = 30, MaskScale = 1.2 ImageScale: 1.1 ↔ 1.0 BlurPeak = 30 // 动画2 峰值模糊 DefaultHalfDurationMs = 1200 // 每半段时长

不同平台 Open 半径不同,因为同一数值在不同渲染管线(WPF BlurEffect、Win2D GaussianBlur、UniformToFill 裁切)下视觉覆盖范围不一致。 因此 WPF 用 270、Avalonia 用 310、WinUI3 用 270,是在不改共享语义的前提下做平台校准。


2,动画拆解

2.1. 动画1 — 眼睑遮罩

2.1. 动画2 — 双层模糊换图

2.1. 动画3 — 整体缩放

ImageScaleGrid以中心为原点,Scale 从 1.1 缓动到 1.0 再 AutoReverse 回到 1.1,营造轻微「呼吸感」。

2.1. 动画合并

上述三路并行执行(Task.WhenAll/Promise.all),总时长仍为每半段 1200ms × 2。


3,五种UI框架 实现

3.1. WPF 实现

WPF 是本项目的参考实现:声明式 XAML +BlurEffect+Storyboard, 与设计师直觉最接近,代码量最少,效果也最「正」。

技术栈要点

  • 遮罩Path+CombinedGeometry.Exclude+BlurEffect Radius=30
  • 图片模糊:双层Image,上层BlurEffect.Radius可动画
  • 动画驱动DoubleAnimation+ 自定义DependencyProperty
  • 缩放ScaleTransform绑在ImageScaleGrid

关键代码:遮罩结构(XAML)
<Path x:Name="MaskPath" Fill="Black" RenderTransformOrigin="0.5,0.5"> <Path.RenderTransform> <ScaleTransform ScaleX="1.2" ScaleY="1.2"/> </Path.RenderTransform> <Path.Effect> <BlurEffect Radius="30" /> </Path.Effect> </Path>
关键代码:动画1 驱动
// 通过 DP 驱动 EllipseGeometry.RadiusY,Storyboard 动画 DP 而非直接动画 Geometry BlinkRadiusY = 270; var animation = new DoubleAnimation { From = 270, To = 10, Duration = TimeSpan.FromMilliseconds(1200), AutoReverse = true, EasingFunction = BlinkEasing.Accelerate }; Storyboard.SetTargetProperty(animation, new PropertyPath(BlinkRadiusYProperty));
✅ 优势
  • BlurEffect一行声明,边缘羽化自然
  • Storyboard 与 UI 线程模型成熟
  • 实现最短,维护成本最低
⚠️ 劣势 / 坑
  • XAML 中BlurEffect会被 Freeze,需代码克隆
  • 仅 Windows 桌面,无法跨 Web / 移动
  • 复杂场景下 Blur 性能依赖 GPU 驱动

效果:


3.2. Web实现

纯前端实现:DOM 叠层 + SVG 遮罩 + CSS Filter / SVG Filter。

技术栈要点

  • 遮罩:SVGpath+fill-rule="evenodd"+feGaussianBlur
  • 图片模糊:叠加 Blur 层,filter: blur(Npx)+ opacity
  • 动画requestAnimationFrame+ 手写 easing(BlinkEngine.animateValue
  • 合并Promise.all

关键代码:遮罩路径 + SVG 模糊
// even-odd:外矩形 + 内椭圆 → 与 WPF Exclude 等价 function buildMaskPathD(ry) { return 'M 0 0 H 400 V 600 H 0 Z' + ' M 200 300 m -500 0 a 500 ' + ry + ' 0 1 0 1000 0 a 500 ' + ry + ' 0 1 0 -1000 0 Z'; } // SVG filter 模糊整个 path(注意:必须先有完整形状再 blur) <filter id="maskBlur"> <feGaussianBlur in="SourceGraphic" stdDeviation="10" /> </filter>
关键代码:动画1 每帧刷新
return animateValue({ from: blinkOpen, to: blinkClosed, durationMs: halfDurationMs, ease: easeIn, autoReverse: true, onUpdate: function (v) { blinkRadiusY = v; render(); } }); // render() 同步更新 scale、mask path d、blur opacity

曾踩的坑:若用 SVG<mask>先硬切椭圆再 blur,边缘永远是硬边。 必须像 WPF 一样——先构造 even-odd 实心形状,再整体高斯模糊

✅ 优势
  • 零安装、易分享、与设计稿联调快
  • 动画逻辑透明,rAF 时间轴完全可控
  • 跨平台(任何现代浏览器)
⚠️ 劣势
  • 每帧render()全量更新,大图 + 多 blur 时 CPU 压力明显
  • CSS/SVG blur 数值与 WPF 不是 1:1,需单独调参(当前 blurPeak/maskBlur=10)
  • 无原生「图层合成」概念,靠 DOM 顺序模拟

效果:


3.3. Avalonia 实现

结构几乎复制 WPF:Path+BlurEffect+ 双层 Grid。 差异主要在布局裁切、UniformToFill留边、以及动画用自研AvaloniaBlinkAnimator(Dispatcher 定时器)而非 WPF Storyboard。

关键代码:遮罩每帧重建 Geometry
private void SetBlinkRadiusY(double value) { _blinkRadiusY = value; MaskPath.Data = BlinkMaskHelper.CreateMaskGeometry(value); MaskPath.InvalidateVisual(); } // 图片模糊:BlurEffect.Radius + 上层 Image Opacity 联动 public static void ApplyBlurRadius(BlurEffect effect, Image blurImage, double radius) { effect.Radius = radius; blurImage.Opacity = radius > 0.01 ? 1 : 0; }
平台补偿

AvaloniaBlinkConstants.BlinkRadiusYOpen = 310— 比 WPF 270 更大,补偿 UniformToFill 在 Avalonia 下的贴边差异。

✅ 优势
  • API 与 WPF 高度相似,迁移成本低
  • 原生BlurEffect遮罩效果接近 WPF
  • 真正跨 Windows / macOS / Linux
⚠️ 劣势 / 周折
  • 多层 Clip / 固定尺寸会导致图片铺不满 — 需删冗余 Border、只保留最外层 Clip
  • 动画2 曾出现错帧闪烁 — Grid 可见性与 blur 重置顺序必须对齐 WPF
  • 定时器驱动不如 Storyboard 省电

效果:


3.4. WinUI 3 实现

WinUI 3没有WPF 那种可直接挂在Path上的BlurEffect。 遮罩模糊改用Win2D CanvasControl每帧 GPU 绘制;图片模糊改用预渲染模糊位图 + Opacity 交叉淡入;缩放走Composition API

关键代码:Win2D 遮罩(替代 Path.BlurEffect)
// BlinkMaskControl.OnCanvasDraw — 每帧重绘 using var maskGeometry = rectGeometry.CombineWith( ellipseGeometry, Matrix3x2.Identity, CanvasGeometryCombine.Exclude); var blurredMask = new GaussianBlurEffect { Source = commandList, BlurAmount = (float)WinUI3BlinkConstants.MaskBlur, // 15,比 WPF 30 轻 BorderMode = EffectBorderMode.Soft }; args.DrawingSession.DrawImage(blurredMask);
关键代码:图片模糊 workaround
// WinUI 无法像 WPF 那样实时动画 BlurEffect.Radius // → 换图时用 Win2D 预生成峰值模糊位图,动画只驱动 Opacity public void SetBlurRadius(double radius) => _image.Opacity = Math.Clamp(radius / BlinkConstants.BlurPeak, 0, 1);
关键代码:Storyboard 动画 RadiusY
return WinUIBlinkStoryboardAnimator.AnimateAsync( _blinkMask, nameof(BlinkMaskControl.RadiusY), WinUI3BlinkConstants.BlinkRadiusYOpen, // 270 BlinkConstants.BlinkRadiusYClosed, // 10 HalfDurationMs, useEaseIn: true, autoReverse: true);

WinUI3 实现周折摘要:

  1. 最初用 16ms 定时器 + 共享库后台线程 → UI 不更新;改为 Storyboard
  2. 遮罩无 BlurEffect → 硬边;引入 Win2D BlinkMaskControl
  3. Win2D BlurAmount=30 过重 → 平台常量降为 15
  4. 列表播放白帧 → 图层 Visibility 时序、grid2 先遮挡再换 grid1
  5. ScaleTransform + 双 Storyboard 曾崩溃 → 缩放改 Composition GPU 路径
✅ 优势
  • Composition 缩放性能优秀
  • Win2D 遮罩模糊可控、GPU 加速
  • 适合现代 Windows 商店 / WinAppSDK 生态
⚠️ 劣势
  • 缺失 WPF 级声明式 Effect,实现复杂度最高
  • 图片 blur 只能「预烘焙 + opacity」,换图有异步加载窗口期
  • 遮罩每帧 Canvas 重绘,需注意 Invalidate 时机
  • 平台特化常量多(BlinkRadiusYOpen、MaskBlur)

效果:


3.5. WinForms 实现

没有 XAML 树:一个SKControl/PictureBox,每帧把图片层 + 遮罩层绘制到同一张位图。所有效果都在 CPU/GPU 混合的 Skia 管线里完成。

关键代码:单帧合成
private Bitmap RenderFrame() { using var surface = SKSurface.Create(new SKImageInfo(400, 600)); var canvas = surface.Canvas; canvas.Clear(SKColors.White); DrawImageLayers(canvas, 400, 600); // 先图片 DrawMask(canvas, 400, 600); // 后遮罩 return SKBitmap.FromImage(surface.Snapshot()).ToBitmap(); } // 遮罩:EvenOdd 路径 + ImageFilter 模糊 using var maskPaint = new SKPaint { ImageFilter = SKImageFilter.CreateBlur(MaskBlur/2f, MaskBlur/2f) }; canvas.DrawPath(maskPath, maskPaint);
✅ 优势
  • 渲染模型简单直观,调试=看一张 bitmap
  • Skia 滤镜能力完整,不依赖 XAML Effect
  • Legacy 项目嵌入成本最低
⚠️ 劣势
  • 每帧全量重绘+ GDI+ 互操作,合并动画 CPU 占用最高
  • 无声明式 UI,布局全靠手工计算 UniformToFill
  • PictureBox 刷新可能闪烁,需手动 Dispose 旧 Bitmap

效果:


4,五种UI框架 对比

维度WPFHTMLAvaloniaWinUI 3WinForms
遮罩模糊Path.BlurEffectSVG feGaussianBlurPath.BlurEffectWin2D 每帧绘制Skia ImageFilter
图片模糊BlurEffect 实时CSS filterBlurEffect 实时预渲染+OpacitySkia 实时
动画驱动StoryboardrAF + 手写插值Dispatcher 定时器Storyboard + Composition定时器 + 全帧重绘
实现复杂度
合并动画性能偏低
视觉还原度基准 100%~90%(参数量)~95%~95%(校准后)~92%
跨平台仅 Windows全平台桌面全平台仅 Windows仅 Windows

WPF真的是很全能!

差异:同一效果用不同技术


5,总结

5.1 遮罩:形状与模糊的先后顺序

眼睑要「糊到人像里」,必须先 even-odd 实心形,再 blur 整形状。 这在 WPF 是一行 Effect;在 HTML 曾因为 SVG mask 顺序错误导致硬边; 在 WinUI3 则完全要用 Win2D 自建管线。

5.2 动画2:图层时序 > 动画曲线

换图闪白不是 easing 问题,而是某一帧两层都不可见。 正确顺序:grid2 先盖住视口 → 在遮挡下更新 grid1 → 再跑 blur 动画; 隐藏 grid2 只用Visibility.Collapsed,不要额外Opacity=0整层。

5.3 平台常量:共享语义 vs 共享数值

BlinkAnimation.Core共享的是动画语义(时长、easing 指数、闭合半径 10), 不是每个像素级参数。Open 半径、MaskBlur 强度允许、也应该分平台校准。

5.4 框架能力边界清单

  • WinUI 3:无 WPF 式 UI Effect;复杂模糊要 Win2D / Composition
  • HTML:无真正图层合成;多 blur 同时运行吃 CPU
  • WPF:Effect 冻结、Dispatcher 绑定;但桌面特效最省心
  • WinForms:最简单 mental model,最贵的是每帧 bitmap

给 UI 体验设计者的结论:先 WPF/HTML 快速验证视觉语法(遮罩几何 + blur + 分层),再按目标平台替换「特效实现层」,而不是指望一份 XAML 到处跑。 「眨眼2」列表播放只是在「眨眼」四层逻辑上叠加换图状态机——读懂本文,就读懂了 80% 的跨平台 UI 动效迁移工作。

WPF版编写起来最容易,Web版给人一种非常柔和的感觉,Winform版也能胜任,但是像素点略微闪烁的感觉,WinUI3的模糊效果很有特色,Avalonia表现比较均衡。我先用WPF控制精准后,再用AI迁移到的其他版本。


6. 源码下载

以上五种效果的完整源码:

https://download.csdn.net/download/LateFrames/93113960

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

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

立即咨询