如何用Jetpack Compose实现返回Shimmer效果的Painter作为Coil占位符?
实现Coil AsyncImage的Shimmer占位符Painter
下面提供两种实现方式,满足你返回Painter作为AsyncImage占位符的需求:
方式一:基于Accompanist Shimmer库实现
这是最便捷的方案,借助官方维护的Accompanist库快速实现Shimmer效果:
- 先添加依赖(Module级别的build.gradle.kts):
dependencies { implementation "com.google.accompanist:accompanist-shimmer:<最新版本号>" }
- 实现
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) } } }
- 使用方式和你示例一致:
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
相关产品推荐
相关产品推荐

