您可以将进度作为参数提供给每个可组合项,同时通过一个动画集中控制进度变化。这样,即使可组合项接连进入合成,它也会以相同的进度进行动画处理。
您可以通过绘制修改器使用 DrawScope 来获取大小,而不是 Modifier.globallyPositioned。
fun Modifier.newShimmer(progress: Float) = this.then(
Modifier
.drawWithContent {
val width = size.width
val height = size.height
val offset = progress * width
drawContent()
val brush = Brush.linearGradient(
colors = listOf(Color.Gray, Color.White, Color.Gray),
start = Offset(offset, 0f),
end = Offset(offset + width, height)
)
drawRect(brush)
}
)
并将进度传递给可组合项
@Composable
fun ShimmerView(progress: Float) {
Box(
Modifier
.size(80.dp)
.newShimmer(progress = progress)
)
}
val transition = rememberInfiniteTransition(label = "shimmer")
val startOffsetX by transition.animateFloat(
initialValue = -2f,
targetValue = 2f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 3000,
)
), label = "shimmer"
)
Text(text = "NEW STYLE")
ShimmerView(progress = startOffsetX)
Spacer(Modifier.height(20.dp))
ShimmerView(progress = startOffsetX)
完整代码
@Preview
@Composable
private fun ShimmerTest() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp)
) {
var showItem by remember {
mutableStateOf(false)
}
Text(text = "OLD STYLE")
ShimmeringComposable() // first composable
Spacer(Modifier.height(20.dp))
ShimmeringComposable() // second composable
Spacer(Modifier.height(20.dp))
if (showItem) {
ShimmeringComposable()
}
Spacer(Modifier.height(20.dp))
val transition = rememberInfiniteTransition(label = "shimmer")
val startOffsetX by transition.animateFloat(
initialValue = -2f,
targetValue = 2f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 3000,
)
), label = "shimmer"
)
Text(text = "NEW STYLE")
ShimmerView(progress = startOffsetX)
Spacer(Modifier.height(20.dp))
ShimmerView(progress = startOffsetX)
Spacer(Modifier.height(20.dp))
if (showItem) {
ShimmerView(progress = startOffsetX)
}
Button(onClick = { showItem = showItem.not() }) {
Text(text = "Show item: $showItem")
}
}
}
@Composable
fun ShimmerView(progress: Float) {
Box(
Modifier
.size(80.dp)
.newShimmer(progress = progress)
)
}
@Composable
fun ShimmeringComposable() {
Box(
Modifier
.size(80.dp)
.shimmer()
)
}
fun Modifier.newShimmer(progress: Float) = this.then(
Modifier
.drawWithContent {
val width = size.width
val height = size.height
val offset = progress * width
drawContent()
val brush = Brush.linearGradient(
colors = listOf(Color.Gray, Color.White, Color.Gray),
start = Offset(offset, 0f),
end = Offset(offset + width, height)
)
drawRect(brush)
}
)
fun Modifier.shimmer(): Modifier = composed {
var size by remember {
mutableStateOf(IntSize.Zero)
}
val width = size.width.toFloat()
val height = size.height.toFloat()
val transition = rememberInfiniteTransition(label = "shimmer")
val startOffsetX by transition.animateFloat(
initialValue = -2 * width,
targetValue = 2 * width,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 3000,
)
), label = "shimmer"
)
Modifier
.background(
brush = Brush.linearGradient(
colors = listOf(Color.Gray, Color.White, Color.Gray),
start = Offset(startOffsetX, 0f),
end = Offset(startOffsetX + width, height)
)
)
.onGloballyPositioned { size = it.size }
}