安卓Compose实现鱼骨加载中效果
安卓Compose实现鱼骨加载中效果
背景与简介
在移动应用开发中,加载中占位动画(Skeleton/骨架屏)能够有效提升用户体验,减少因数据延迟带来的焦虑感。鱼骨加载效果是一种常见的骨架屏动画,模拟内容结构,配合闪烁动画(Shimmer)让界面在数据加载时更具活力。Jetpack Compose 作为 Android 现代声明式UI框架,极大简化了骨架屏实现难度。
适用场景
- 网络请求数据加载时的占位
- 列表、卡片等内容结构明确的页面
- 需要提升加载体验的场景
Compose骨架屏与传统View实现对比
- 传统View实现骨架屏通常需要自定义View、手动绘制、管理动画,代码复杂且维护成本高。
- Compose下,借助第三方库如 compose-shimmer,仅需简单修饰符组合即可实现灵活的骨架屏动画,代码更简洁、可读性更强。
Shimmer动画原理简介
Shimmer是一种通过渐变色块横向移动,模拟光影流动的动画效果。其本质是利用Canvas绘制渐变蒙版,并通过属性动画不断平移,实现闪烁流动的视觉效果。compose-shimmer库对这一过程进行了高度封装,开发者只需一行Modifier即可应用。
安卓如何实现如下图类似鱼骨加载中效果
我们需要使用compose-shimmer
,添加依赖 (build.gradle)
implementation("com.valentinilk.shimmer:compose-shimmer:1.3.2")
最新的版本号可以参见 https://github.com/valentinilk/compose-shimmer
定义一个状态类 UiState
用于管理加载状态和数据:
data class UiState(
val isLoading: Boolean = true, // 控制是否处于加载状态
val data: List<Order> = emptyList() // 实际数据列表
) : IState
UiState
包含了 isLoading
布尔值来指示当前是否正在加载数据,以及 data
列表来存储实际的订单数据。当 isLoading
为 true
时,UI 将显示占位符(鱼骨效果),否则显示实际数据。
在 LazyColumn
中根据 UiState
的 isLoading
状态来显示不同的内容:
当 isLoading
为 true
时,我们渲染固定数量的占位符(这里是5个),并传入空的字符串作为占位内容。这些占位符将通过 OrderItemView
应用鱼骨加载效果。
当 isLoading
为 false
时,我们渲染实际的 viewState.data
中的数据。
LazyColumn(
modifier = Modifier.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
if (viewState.isLoading) {
items(5) { index ->
// 传入空的字符占位
OrderItemView(
order = Order(
type = " ",
status = " ",
time = " ",
startAddress = " ",
endAddress = " "
),
viewState = viewState
)
}
} else {
items(viewState.data.size) { index ->
OrderItemView(
order = viewState.data[index],
viewState = viewState
)
}
}
}
OrderItemView
的部分参考实现如下:
OrderItemView
是一个可组合函数,它根据 viewState.isLoading
的值来决定是显示鱼骨加载效果还是实际的订单信息。关键在于 Modifier.shimmer()
的应用。
@Composable
fun OrderItemView(order: Order, viewState: UiState) {
// 通过 viewState.isLoading 控制显示
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp)
.then(if (viewState.isLoading) Modifier.shimmer() else Modifier),
shape = RoundedCornerShape(16.dp),
elevation = CardDefaults.cardElevation(4.dp),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
// 部分实现, 通过 viewState.isLoading 控制显示
Text(
modifier = Modifier
.background(
color = if (viewState.isLoading) Color.LightGray else Color.Transparent,
shape = RoundedCornerShape(2.dp)
)
.then(if (viewState.isLoading) Modifier.shimmer() else Modifier), // shimmer 作用在 Text 上,使其背景闪烁
text = order.type,
style = MaterialTheme.typography.titleMedium
)
}
}
常见问题与优化建议
- 闪烁效果不明显?
- 请确保
Modifier.shimmer()
应用在background
等绘制修饰符之后。 - 可调整骨架色(如
Color.LightGray
)和Shimmer参数(如高亮色、动画速度)增强对比度。
- 请确保
- 骨架屏与内容跳变明显?
- 建议骨架屏布局与实际内容布局保持一致,避免切换时界面抖动。
- 性能影响?
- compose-shimmer 性能较优,但大量骨架项或复杂动画时建议限制骨架数量,避免过度绘制。
- 自定义骨架形状?
- 可通过
background
的shape
参数自定义圆角、椭圆等形状,灵活适配不同UI风格。
- 可通过
参考资料
- compose-shimmer官方文档:https://github.com/valentinilk/compose-shimmer
- Jetpack Compose官方文档:https://developer.android.com/jetpack/compose
- 完整代码实现: https://gitee.com/chenjim/ArchitectureMVI 中 ShimmerScreen.kt
本文链接:安卓Compose实现鱼骨加载中效果 - https://www.h89.cn/archives/404.html
版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。
![]()