ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

gpui-kit Skeleton 骨架屏组件指南:加载占位、脉冲动画与主题定制

gpui-kit Skeleton 骨架屏组件指南:加载占位、脉冲动画与主题定制 gpui-kit Skeleton 骨架屏组件指南加载占位、脉冲动画与主题定制【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kitSkeleton骨架屏是 gpui-kit 提供的内容加载占位组件在真实数据尚未就绪时用带动画的占位块替代最终内容既向用户传达内容正在加载的反馈又通过占据与真实内容相近的版面来保持布局稳定。本指南以中文文档为骨架结合 skeleton.rs 源码实现系统讲解 Skeleton 的导入方式、各类占位形态的搭建方法、内置脉冲动画的底层原理、尺寸控制技巧与主题定制方案。读完本文你将能够在 gpui-kit 应用中为列表、卡片、表格、表单等场景快速搭建专业的加载态界面。组件定位与设计理念Skeleton 在 gpui-kit 组件库中位于 crates/component/src/skeleton.rs并在 crates/component/src/lib.rs 中以pub mod skeleton;公开导出。从源码结构看它不是一个独立渲染的复杂控件而是基于 GPUI 的IntoElement派生宏构建的轻量元素#[derive(IntoElement)] pub struct Skeleton { style: StyleRefinement, secondary: bool, }该结构只有两个字段style样式细化可通过 Styled trait 链式叠加尺寸、圆角等与secondary是否使用更柔和的次级颜色。这种极简结构 完全交由样式工具定制外观的设计决定了 Skeleton 的使用哲学组件本身不预设形状枚举占位形态完全由 gpui 的尺寸与圆角工具组合出来。导入在 Rust 代码中按如下方式导入 Skeletonuse gpui_kit::component::skeleton::Skeleton;同时由于骨架屏大量依赖 gpui 的布局与样式工具v_flex、h_flex、px、Styledtrait 等实际使用时通常还需要引入use gpui::{px, Styled}; // 像素尺寸与样式链式方法 use gpui_kit::component::v_flex; // 或 h_flex用于纵向/横向布局基础用法最简单的骨架屏只有一个块Skeleton::new()在RenderOnce::render实现skeleton.rs中它会被渲染为一个带内置动画的div默认占满整行宽度w_full且高度为 4h_416px背景色取自主题的skeleton颜色。也就是说单写一个Skeleton::new()即可得到一条通栏的加载占位条随后可通过样式链覆盖宽高与圆角。常用占位形态文本行占位模拟单行或多行文本加载利用h_4/h_3控制行高、w(px(...))控制行宽// 单行文本 Skeleton::new() .w(px(250.)) .h_4() .rounded_md() // 多行文本宽度递减模拟自然换行 v_flex() .gap_2() .child(Skeleton::new().w(px(250.)).h_4().rounded_md()) .child(Skeleton::new().w(px(200.)).h_4().rounded_md()) .child(Skeleton::new().w(px(180.)).h_4().rounded_md())圆形占位头像、图标等圆形区域用rounded_full实现。size_12是 48×48px 的正方形再裁圆角// 头像占位 Skeleton::new() .size_12() .rounded_full() // 自定义尺寸的头像占位 Skeleton::new() .w(px(64.)) .h(px(64.)) .rounded_full()矩形占位卡片封面、按钮等矩形区域直接指定宽高// 卡片图片占位 Skeleton::new() .w(px(250.)) .h(px(125.)) .rounded_md() // 按钮占位 Skeleton::new() .w(px(120.)) .h(px(40.)) .rounded_md()不同形状组合骨架屏可以覆盖几乎所有版面元素常见组合如下Skeleton::new().w(px(200.)).h_4().rounded_sm() // 紧凑文本 Skeleton::new().size_20().rounded_md() // 方形图片 Skeleton::new().w_full().h(px(200.)).rounded_lg() // 通栏横幅 Skeleton::new().size_6().rounded_md() // 小图标Secondary 变体当占位需要比主骨架更弱的存在感例如列表里的次要行时调用.secondary()Skeleton::new() .secondary() .w(px(200.)) .h_4() .rounded_md()该方法的源码实现非常直接skeleton.rspub fn secondary(mut self) - Self { self.secondary true; self }而在渲染时skeleton.rs次级变体会对主题骨架色应用50% 透明度.bg(if self.secondary { cx.theme().skeleton.opacity(0.5).into() } else { cx.theme().skeleton })注意这里用的是 HSLA 的opacity直接调制因此无论主题色是浅是深次级变体都能得到一致的柔和观感。内置脉冲动画Skeleton 自带脉冲pulse动画无需任何额外配置。源码中的动画定义skeleton.rs如下.with_animation( skeleton, Animation::new(Duration::from_secs(2)) .repeat() .with_easing(bounce(ease_in_out)), move |this, delta| { let v 1.0 - delta * 0.5; this.opacity(v) }, )对照中文文档的动画行为描述可以逐一在源码中印证文档描述源码实现持续循环播放周期 2 秒Animation::new(Duration::from_secs(2))配合.repeat()使用 bounce easing并带有 ease-in-out 变化.with_easing(bounce(ease_in_out))透明度在 100% 和 50% 之间往返回调v 1.0 - delta * 0.5delta从 0 到 1 时v从 1.0 降到 0.5循环往复自动重复.repeat()该动画不可关闭它不暴露开关参数因为闪烁的占位本身就是加载状态最重要的视觉提示关闭后用户将无法区分空白与加载中。这一点与中文文档的说明完全一致。值得注意的细节是动画名固定为skeleton它通过 GPUI 的AnimationExt与元素的opacity样式绑定透明度以 0.5 为下限保证占位块始终清晰可见不会完全消失造成闪烁断层。尺寸控制Skeleton没有预设的尺寸枚举这正是它与许多 UI 库骨架屏组件的关键区别。占位形态完全交给 gpui 的尺寸工具常用的组合如下// 高度工具间距基数 × 4pxh_312px, h_416px, h_520px, h_624px Skeleton::new().h_3() Skeleton::new().h_4() Skeleton::new().h_5() Skeleton::new().h_6() // 宽度工具 Skeleton::new().w(px(100.)) // 固定 100px Skeleton::new().w(px(200.)) // 固定 200px Skeleton::new().w_full() // 通栏 Skeleton::new().w_1_2() // 父容器 50% 宽 // 正方形尺寸size_416px, size_832px, size_1248px, size_1664px Skeleton::new().size_4() Skeleton::new().size_8() Skeleton::new().size_12() Skeleton::new().size_16()配合rounded_sm/md/lg/full圆角工具即可精确复刻目标内容的几何形状。实战示例以下示例均为加载态的完整布局骨架可直接组合进真实页面。资料卡片加载中模拟头像 姓名/邮箱 两行简介的 profile 卡片v_flex() .gap_4() .p_4() .border_1() .border_color(cx.theme().border) .rounded(cx.theme().radius_lg) .child( h_flex() .gap_3() .items_center() .child(Skeleton::new().size_12().rounded_full()) // 头像 .child( v_flex() .gap_2() .child(Skeleton::new().w(px(120.)).h_4().rounded_md()) // 姓名 .child(Skeleton::new().w(px(100.)).h_3().rounded_md()) // 邮箱 ) ) .child( v_flex() .gap_2() .child(Skeleton::new().w_full().h_4().rounded_md()) // 简介第一行 .child(Skeleton::new().w(px(200.)).h_4().rounded_md()) // 简介第二行 )这里使用了cx.theme().border与cx.theme().radius_lg需配合ActiveThemetrait让加载骨架与最终内容保持完全一致的边框与圆角。文章列表加载中用childrenmap批量生成 3 条缩略图 标题/摘要/日期的列表项v_flex() .gap_6() .children((0..3).map(|_| { h_flex() .gap_4() .child(Skeleton::new().w(px(120.)).h(px(80.)).rounded_md()) // 缩略图 .child( v_flex() .gap_2() .flex_1() .child(Skeleton::new().w_full().h_5().rounded_md()) // 标题 .child(Skeleton::new().w(px(300.)).h_4().rounded_md()) // 摘要行1 .child(Skeleton::new().w(px(250.)).h_4().rounded_md()) // 摘要行2 .child(Skeleton::new().w(px(100.)).h_3().rounded_md()) // 日期 ) }))表格行加载中模拟 5 行表格数据用border_b_1复刻行分隔线v_flex() .gap_2() .children((0..5).map(|_| { h_flex() .gap_4() .p_3() .border_b_1() .border_color(cx.theme().border) .child(Skeleton::new().size_8().rounded_full()) // 状态指示 .child(Skeleton::new().w(px(150.)).h_4().rounded_md()) // 名称 .child(Skeleton::new().w(px(200.)).h_4().rounded_md()) // 邮箱 .child(Skeleton::new().w(px(80.)).h_4().rounded_md()) // 角色 .child(Skeleton::new().w(px(60.)).h_4().rounded_md()) // 操作 }))按钮加载态一组按钮主按钮、次按钮、图标按钮的占位h_flex() .gap_3() .child(Skeleton::new().w(px(80.)).h(px(36.)).rounded_md()) // 主按钮 .child(Skeleton::new().w(px(70.)).h(px(36.)).rounded_md()) // 次按钮 .child(Skeleton::new().size_9().rounded_md()) // 图标按钮表单字段加载态标签 输入框、标签 多行文本域v_flex() .gap_4() .child( v_flex() .gap_1() .child(Skeleton::new().w(px(60.)).h_4().rounded_md()) // 标签 .child(Skeleton::new().w_full().h(px(40.)).rounded_md()) // 输入框 ) .child( v_flex() .gap_1() .child(Skeleton::new().w(px(80.)).h_4().rounded_md()) // 标签 .child(Skeleton::new().w_full().h(px(120.)).rounded_md()) // 文本域 )条件加载在实际应用中通常以布尔状态切换骨架屏与真实内容if loading { Skeleton::new().w(px(200.)).h_4().rounded_md() } else { div().child(Actual content here) }这也是骨架屏的核心价值先渲染与目标内容同构的占位数据到达后原位替换避免布局跳动。主题定制Skeleton 的背景色由主题 tokenskeleton.background驱动。在 schema.rs 中该 token 被定义为可选的SharedString/// Skeleton background color. #[serde(rename skeleton.background)] pub skeleton: OptionSharedString,如果主题没有显式配置会按 schema.rs 的 fallback 逻辑回退到tokens.secondaryapply_background_color!(skeleton, fallback tokens.secondary);这也是中文文档中未配置时回退到 secondary的源码依据。组件侧在 theme_color.rs 中持有解析后的skeleton: Hsla颜色渲染时直接取用。内置默认主题 default-theme.json 给出了明暗两套默认值模式取值浅色lightskeleton.background: #f5f5f5深色darkskeleton.background: #171717自定义时在主题 JSON 中覆盖该 token 即可{ skeleton.background: #e2e8f0 }两条主题相关的补充说明回退链skeleton.background缺失 → 使用secondary色若希望全局联动直接调整secondary相关 token 即可影响所有未显式配置 skeleton 的界面。secondary(true)变体对骨架色施加 50% 透明度用于同一页面中需要弱化的次级占位例如列表的次要行视觉上比主骨架更含蓄。仓库内的实际应用Skeleton 不是孤立的演示组件它已被组件库内部用于真实加载态。例如 crates/component/src/list/loading.rs 用它实现了ListItem的加载列表项——每个LoadingItem渲染两行骨架主行h_5、次级行secondary()并禁用交互ListItem::new(skeleton).disabled(true).child( v_flex() .gap_1p5() .overflow_hidden() .child(Skeleton::new().h_5().w_48().max_w_full()) .child(Skeleton::new().secondary().h_3().w_64().max_w_full()), )同样的模式也出现在表格加载态table/loading.rs。这印证了文档推荐的用法用secondary()区分主次信息层级用max_w_full防止超宽溢出用overflow_hidden保证极端宽度下骨架不撑破容器——这些都是在真实组件中沉淀下来的实践细节。小结gpui-kit 的 Skeleton 组件用极简的 API 承载了完整的加载态设计能力默认通栏条状占位、Styled驱动的任意形状塑造、secondary次级变体、2 秒 bounce 脉冲动画不可关闭以及经由skeleton.backgroundtoken 的完整主题定制。将其与列表、表格等数据型组件配合使用即可在数据到达前为用户提供流畅、稳定、与最终界面同构的加载体验。【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表