5.9 KiB
骨架页(Skeleton Screen)实施计划
问题分析
当前首次启动时,用户看到的现象:
- 全屏窗口立即显示,但状态栏组件全部
IsVisible="False"(空白) - 头像区域只有 fallback 文字 "U",尺寸未计算(显得巨大)
- 底部 Dock 任务栏已经渲染但内容为空
- 壁纸加载完成前,桌面区域是透明/黑色的
- 整体看起来就是一个"Dock 栏覆盖全屏 + 巨大头像"的半成品状态
根本原因:OnOpened 中有大量同步初始化操作(壁纸解码、组件布局、启动器扫描等),在它们完成之前,UI 元素要么不可见要么处于默认状态。
方案概述
在 DesktopPage 层添加一个骨架遮罩层,覆盖在真实内容之上,在初始化完成前显示骨架占位,初始化完成后淡出消失。
骨架页布局
┌──────────────────────────────────────────────────────────────┐
│ [状态栏骨架] │
│ ┌─────────┐ ┌──────────────────┐ ┌─────────┐ │
│ │ ○ 头像 │ │ ████ 时钟 ████ │ │ ○ ○ │ │
│ └─────────┘ └──────────────────┘ └─────────┘ │
│ │
│ (桌面区域 - 壁纸层) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ [Dock 任务栏骨架] │ │
│ │ ██ ████████ ████████ ████████ ████████ ○ │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
骨架元素
| 区域 | 骨架元素 | 形状 | 说明 |
|---|---|---|---|
| 状态栏-中间 | 时钟骨架 | 圆角矩形(DesignCornerRadiusComponent) |
模拟 ClockWidget 的胶囊形状 |
| 状态栏-中间 | 文本胶囊骨架 | 圆角矩形(较小) | 模拟 TextCapsuleWidget |
| 底部 Dock | 头像骨架 | 圆形 | 模拟 TaskbarProfileAvatarBorder |
| 底部 Dock | 操作按钮骨架 | 圆角矩形 | 模拟任务栏按钮 |
| 底部 Dock | 分隔线骨架 | 细长矩形 | 模拟按钮间分隔 |
骨架样式
-
颜色:使用
AdaptiveGlassPanelBackgroundBrush作为基础色,叠加一个 Shimmer 动画(微光扫过效果) -
圆角:与真实组件一致,使用
DesignCornerRadiusComponent -
动画:Shimmer 微光从左到右扫过,周期 2s,使用
FluttermotionToken缓动
实施步骤
Step 1: 创建 Shimmer 动画画刷
在 GlassModule.axaml 或新建 SkeletonStyles.axaml 中定义:
-
创建
ShimmerBrush:一个LinearGradientBrush,包含高光条带 -
创建
ShimmerAnimationstoryboard:让高光条带从左到右移动 -
定义
skeleton-shimmer样式类:应用 ShimmerBrush + 动画
Step 2: 在 MainWindow.axaml 中添加骨架遮罩层
在 DesktopPage Grid 内、所有真实内容之上添加一个 Grid x:Name="SkeletonOverlay":
-
初始
IsVisible="True",ZIndex="999" -
包含状态栏骨架区域和底部 Dock 骨架区域
-
使用与真实布局相同的 Grid RowDefinitions,确保骨架元素对齐
Step 3: 在 MainWindow.axaml.cs 中控制骨架显示/隐藏
-
在
OnOpened开始时,骨架层可见 -
在
OnOpened末尾(所有初始化完成后),调用HideSkeletonOverlayAsync() -
HideSkeletonOverlayAsync():播放淡出动画 → 设置IsVisible="False" -
如果启用了滑入滑出过渡,骨架层在入场动画期间也应可见,入场动画完成后再淡出
Step 4: 骨架元素尺寸适配
-
骨架元素需要在
ApplyTaskbarSettings()后更新尺寸(因为taskbarCellHeight等值在 OnOpened 中才计算) -
或者在 XAML 中使用相对尺寸(百分比/比例),避免依赖代码计算
Step 5: 与窗口过渡动画的协调
-
入场动画(
PrepareEnterAnimation/PlayEnterAnimation)期间,骨架层应保持可见 -
入场动画完成后,先短暂显示骨架(~100ms),然后淡出骨架
-
退场动画时,无需特殊处理(骨架已隐藏)
涉及文件
| 文件 | 改动类型 |
|---|---|
Styles/SkeletonStyles.axaml(新建) |
Shimmer 画刷 + 骨架样式类 |
Views/MainWindow.axaml |
添加 SkeletonOverlay 层 |
Views/MainWindow.axaml.cs |
骨架显示/隐藏逻辑 |
App.axaml |
引入 SkeletonStyles 资源 |
不涉及的文件
-
不修改组件代码(ClockWidget、TextCapsuleWidget 等)
-
不修改设置系统
-
不修改 App.axaml.cs 的启动流程