You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jetpack Compose实现返回Shimmer效果的Painter作为Coil占位符?

实现Coil AsyncImage的Shimmer占位符Painter

下面提供两种实现方式,满足你返回Painter作为AsyncImage占位符的需求:

方式一:基于Accompanist Shimmer库实现

这是最便捷的方案,借助官方维护的Accompanist库快速实现Shimmer效果:

  1. 先添加依赖(Module级别的build.gradle.kts):
dependencies {
    implementation "com.google.accompanist:accompanist-shimmer:<最新版本号>"
}
  1. 实现shimmerEffectPainter可组合函数:
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.google.accompanist.shimmer.rememberShimmerBrush

@Composable
fun shimmerEffectPainter(
    baseColor: Color = Color.LightGray.copy(alpha = 0.3f),
    highlightColor: Color = Color.LightGray.copy(alpha = 0.6f),
    shimmerWidth: Dp = 200.dp
): Painter {
    val shimmerBrush = rememberShimmerBrush(
        baseColor = baseColor,
        highlightColor = highlightColor,
        width = shimmerWidth
    )
    
    return object : Painter() {
        override val intrinsicSize: Size
            get() = Size.Unspecified

        override fun DrawScope.onDraw() {
            drawRect(brush = shimmerBrush)
        }
    }
}
  1. 使用方式和你示例一致:
AsyncImage(
    model = url,
    contentDescription = "加载的图片",
    placeholder = { shimmerEffectPainter() }
)

方式二:自定义无依赖实现

如果不想引入额外库,可以自己实现Shimmer动画逻辑:

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CornerRadius
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
fun shimmerEffectPainter(
    baseColor: Color = Color.LightGray.copy(alpha = 0.3f),
    highlightColor: Color = Color.LightGray.copy(alpha = 0.6f),
    animationDuration: Int = 1500,
    cornerRadius: Dp = 0.dp
): Painter {
    val infiniteTransition = rememberInfiniteTransition()
    val shimmerOffset by infiniteTransition.animateFloat(
        initialValue = -1f,
        targetValue = 2f,
        animationSpec = infiniteRepeatable(
            animation = tween(animationDuration, easing = LinearEasing),
            repeatMode = RepeatMode.Restart
        )
    )

    val shimmerBrush = Brush.linearGradient(
        colors = listOf(baseColor, highlightColor, baseColor),
        start = Offset(shimmerOffset * size.width, 0f),
        end = Offset((shimmerOffset + 1) * size.width, 0f)
    )

    return object : Painter() {
        override val intrinsicSize: Size
            get() = Size.Unspecified

        override fun DrawScope.onDraw() {
            if (cornerRadius.value == 0f) {
                drawRect(brush = shimmerBrush)
            } else {
                drawRoundRect(
                    brush = shimmerBrush,
                    cornerRadius = CornerRadius(cornerRadius.toPx())
                )
            }
        }
    }
}

这个版本支持自定义圆角和动画时长,使用方式和之前完全相同。

内容的提问来源于stack exchange,提问作者Roony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:12:42