「眨眼」UI 特效 - 在 Winform/WPF/WinUI3/Avalonia/Web 的实现

📅 2026/7/13 2:44:51
「眨眼」UI 特效 - 在 Winform/WPF/WinUI3/Avalonia/Web 的实现
目录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-ruleevenodd再对整个形状做静态高斯模糊Radius ≈ 30 使眼睑边缘与人像产生柔和过渡。动画过程中只改变椭圆的RadiusY270 → 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 BlurEffectStoryboard 与设计师直觉最接近代码量最少效果也最「正」。技术栈要点遮罩PathCombinedGeometry.ExcludeBlurEffect Radius30图片模糊双层Image上层BlurEffect.Radius可动画动画驱动DoubleAnimation 自定义DependencyProperty缩放ScaleTransform绑在ImageScaleGrid关键代码遮罩结构XAMLPath x:NameMaskPath FillBlack RenderTransformOrigin0.5,0.5 Path.RenderTransform ScaleTransform ScaleX1.2 ScaleY1.2/ /Path.RenderTransform Path.Effect BlurEffect Radius30 / /Path.Effect /Path关键代码动画1 驱动// 通过 DP 驱动 EllipseGeometry.RadiusYStoryboard 动画 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。技术栈要点遮罩SVGpathfill-ruleevenoddfeGaussianBlur图片模糊叠加 Blur 层filter: blur(Npx) opacity动画requestAnimationFrame 手写 easingBlinkEngine.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 idmaskBlur feGaussianBlur inSourceGraphic stdDeviation10 / /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曾踩的坑若用 SVGmask先硬切椭圆再 blur边缘永远是硬边。 必须像 WPF 一样——先构造 even-odd 实心形状再整体高斯模糊。✅ 优势零安装、易分享、与设计稿联调快动画逻辑透明rAF 时间轴完全可控跨平台任何现代浏览器⚠️ 劣势每帧render()全量更新大图 多 blur 时 CPU 压力明显CSS/SVG blur 数值与 WPF 不是 1:1需单独调参当前 blurPeak/maskBlur10无原生「图层合成」概念靠 DOM 顺序模拟效果3.3. Avalonia 实现结构几乎复制 WPFPathBlurEffect 双层 Grid。 差异主要在布局裁切、UniformToFill留边、以及动画用自研AvaloniaBlinkAnimatorDispatcher 定时器而非 WPF Storyboard。关键代码遮罩每帧重建 Geometryprivate 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 动画 RadiusYreturn WinUIBlinkStoryboardAnimator.AnimateAsync( _blinkMask, nameof(BlinkMaskControl.RadiusY), WinUI3BlinkConstants.BlinkRadiusYOpen, // 270 BlinkConstants.BlinkRadiusYClosed, // 10 HalfDurationMs, useEaseIn: true, autoReverse: true);WinUI3 实现周折摘要最初用 16ms 定时器 共享库后台线程 → UI 不更新改为 Storyboard遮罩无 BlurEffect → 硬边引入 Win2D BlinkMaskControlWin2D BlurAmount30 过重 → 平台常量降为 15列表播放白帧 → 图层 Visibility 时序、grid2 先遮挡再换 grid1ScaleTransform 双 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);✅ 优势渲染模型简单直观调试看一张 bitmapSkia 滤镜能力完整不依赖 XAML EffectLegacy 项目嵌入成本最低⚠️ 劣势每帧全量重绘 GDI 互操作合并动画 CPU 占用最高无声明式 UI布局全靠手工计算 UniformToFillPictureBox 刷新可能闪烁需手动 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仅 WindowsWPF真的是很全能差异同一效果用不同技术5总结5.1 遮罩形状与模糊的先后顺序眼睑要「糊到人像里」必须先 even-odd 实心形再 blur 整形状。 这在 WPF 是一行 Effect在 HTML 曾因为 SVG mask 顺序错误导致硬边 在 WinUI3 则完全要用 Win2D 自建管线。5.2 动画2图层时序 动画曲线换图闪白不是 easing 问题而是某一帧两层都不可见。 正确顺序grid2 先盖住视口 → 在遮挡下更新 grid1 → 再跑 blur 动画 隐藏 grid2 只用Visibility.Collapsed不要额外Opacity0整层。5.3 平台常量共享语义 vs 共享数值BlinkAnimation.Core共享的是动画语义时长、easing 指数、闭合半径 10 不是每个像素级参数。Open 半径、MaskBlur 强度允许、也应该分平台校准。5.4 框架能力边界清单WinUI 3无 WPF 式 UI Effect复杂模糊要 Win2D / CompositionHTML无真正图层合成多 blur 同时运行吃 CPUWPFEffect 冻结、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