安卓Compose实现鱼骨加载中效果

安卓Compose实现鱼骨加载中效果

文章目录

本文首发地址 https://h89.cn/archives/404.html

背景与简介

在移动应用开发中,加载中占位动画(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 用于管理加载状态和数据:

kotlin 复制代码
data class UiState(
    val isLoading: Boolean = true, // 控制是否处于加载状态
    val data: List<Order> = emptyList() // 实际数据列表
) : IState

UiState 包含了 isLoading 布尔值来指示当前是否正在加载数据,以及 data 列表来存储实际的订单数据。当 isLoadingtrue 时,UI 将显示占位符(鱼骨效果),否则显示实际数据。

LazyColumn 中根据 UiStateisLoading 状态来显示不同的内容:

isLoadingtrue 时,我们渲染固定数量的占位符(这里是5个),并传入空的字符串作为占位内容。这些占位符将通过 OrderItemView 应用鱼骨加载效果。

isLoadingfalse 时,我们渲染实际的 viewState.data 中的数据。

kotlin 复制代码
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() 的应用。

kotlin 复制代码
@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 性能较优,但大量骨架项或复杂动画时建议限制骨架数量,避免过度绘制。
  • 自定义骨架形状?
    • 可通过 backgroundshape 参数自定义圆角、椭圆等形状,灵活适配不同UI风格。

参考资料

相关推荐
xiaoshiquan120615 分钟前
as强制过滤指定依赖版本库,解决该依赖不同版本冲突
android
2501_929157682 小时前
Switch 20.5.0系统最新PSP模拟器懒人包
android·游戏·ios·pdf
用户094 小时前
Kotlin Flow的6个必知高阶技巧
android·面试·kotlin
用户094 小时前
Flutter插件与包的本质差异
android·flutter·面试
用户094 小时前
Jetpack Compose静态与动态CompositionLocal深度解析
android·面试·kotlin
聆风吟º7 小时前
【Spring Boot 报错已解决】别让端口配置卡壳!Spring Boot “Binding to target failed” 报错解决思路
android·java·spring boot
非专业程序员Ping14 小时前
HarfBuzz概览
android·ios·swift·font
Jeled15 小时前
「高级 Android 架构师成长路线」的第 1 阶段 —— 强化体系与架构思维(Clean Architecture 实战)
android·kotlin·android studio·1024程序员节
明道源码17 小时前
Kotlin 控制流、函数、Lambda、高阶函数
android·开发语言·kotlin
消失的旧时光-194319 小时前
Kotlin × Gson:为什么遍历 JsonObject 要用 entrySet()
android·kotlin·数据处理·1024程序员节