在Compose中无限并可逆地动画线性渐变(刷子)。

huangapple go评论79阅读模式
英文:

Animate Linear Gradient (Brush) infinitely and reversely in Compose

问题

初始状态如下 (animatedOffset = 0f)

在Compose中无限并可逆地动画线性渐变(刷子)。

1f 时,我想要获取反向渐变:

在Compose中无限并可逆地动画线性渐变(刷子)。

当前代码:

val transition = rememberInfiniteTransition(label = "NavIconGradientAnim")

val animatedOffset by transition.animateFloat(
    initialValue = 0f, targetValue = 1f,
    label = "NavIconGradientAnimOffset",
    animationSpec = infiniteRepeatable(
        animation = tween(1500, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    )
)
Image(
    painterResource(id = item.icon),
    contentDescription = null,
    modifier = Modifier.drawWithCache {
        onDrawWithContent {
            with(drawContext.canvas.nativeCanvas) {
                val angle = 45f
                val endX = drawContext.size.width
                val endY = (endX * kotlin.math.tan(Math.toRadians(angle.toDouble()))).toFloat()

                val checkPoint = saveLayer(null, null)
                drawContent()
                val gradient = Brush.linearGradient(
                    colors = listOf(Color.Blue, Color.Yellow),
                    start = Offset(animatedOffset * endX, animatedOffset * endY),
                    end = Offset(endX, endX)
                )
                drawRect(
                    brush = gradient,
                    blendMode = BlendMode.SrcIn
                )
                restoreToCount(checkPoint)
            }
        }
    }
)

我尝试设置

end = Offset(endX - animatedOffset * endX, endY - animatedOffset * endY),

但它看起来不好(GIF 预览):

在Compose中无限并可逆地动画线性渐变(刷子)。

颜色变化突然。

英文:

Initial State looks like this (animatedOffset = 0f)

在Compose中无限并可逆地动画线性渐变(刷子)。

at 1f I want to get the reversed gradient:

在Compose中无限并可逆地动画线性渐变(刷子)。

Current code:

val transition = rememberInfiniteTransition(label = "NavIconGradientAnim")

val animatedOffset by transition.animateFloat(
    initialValue = 0f, targetValue = 1f,
    label = "NavIconGradientAnimOffset",
    animationSpec = infiniteRepeatable(
        animation = tween(1500, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    )
)
Image(
    painterResource(id = item.icon),
    contentDescription = null,
    modifier = Modifier.drawWithCache {
        onDrawWithContent {
            with(drawContext.canvas.nativeCanvas) {
                val angle = 45f
                val endX = drawContext.size.width
                val endY = (endX * kotlin.math.tan(Math.toRadians(angle.toDouble()))).toFloat()

                val checkPoint = saveLayer(null, null)
                drawContent()
                val gradient = Brush.linearGradient(
                    colors = listOf(Color.Blue, Color.Yellow),
                    start = Offset(animatedOffset * endX, animatedOffset * endY),
                    end = Offset(endX, endX)
                )
                drawRect(
                    brush = gradient,
                    blendMode = BlendMode.SrcIn
                )
                restoreToCount(checkPoint)
            }
        }
    }
)

I tried to set

end = Offset(endX - animatedOffset * endX, endY - animatedOffset * endY),

but it doesn't look good (GIF preview):

在Compose中无限并可逆地动画线性渐变(刷子)。

it changes color abruptly

答案1

得分: 1

以下是翻译好的部分:

有几种方法可以做到这一点,你不必计算切线。

一种方法是

val limit = 1.5f

val transition = rememberInfiniteTransition(label = "shimmer")
val progressAnimated by transition.animateFloat(
    initialValue = -limit,
    targetValue = limit,
    animationSpec = infiniteRepeatable(
        animation = tween(1500, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ), label = "shimmer"
)

并设置画笔(brush):

val width = size.width
val height = size.height

val offset = width * progress
val gradientWidth = width

val brush = Brush.linearGradient(
    colors = gradientColors,
    start = Offset(offset, 0f),
    end = Offset(offset + gradientWidth, height)
)

结果

在Compose中无限并可逆地动画线性渐变(刷子)。

演示

@Preview
@Composable
private fun SingleGradientTest() {

    Column(
        Modifier.padding(20.dp)
    ) {
        val painterStar = painterResource(id = R.drawable.star_foreground)

        val limit = 1.5f
        var progress by remember {
            mutableStateOf(-limit)
        }

        val transition = rememberInfiniteTransition(label = "shimmer")
        val progressAnimated by transition.animateFloat(
            initialValue = -limit,
            targetValue = limit,
            animationSpec = infiniteRepeatable(
                animation = tween(1500, easing = LinearEasing),
                repeatMode = RepeatMode.Reverse
            ), label = "shimmer"
        )

        Box(
            modifier = Modifier
                .fillMaxWidth()
                .aspectRatio(1f)
                .drawWithCache {
                    val width = size.width
                    val height = size.height

                    val offset = width * progress
                    val gradientWidth = width

                    val brush = Brush.linearGradient(
                        colors = gradientColors,
                        start = Offset(offset, 0f),
                        end = Offset(offset + gradientWidth, height)
                    )

                    onDrawBehind {
                        drawRect(
                            brush = brush,
                            blendMode = BlendMode.SrcIn
                        )
                    }
                }
        )

        Box(
            modifier = Modifier
                .size(100.dp)
                .graphicsLayer {
                    compositingStrategy = CompositingStrategy.Offscreen
                }
                .drawWithCache {
                    val width = size.width
                    val height = size.height

                    val offset = width * progress
                    val gradientWidth = width


                    val brush = Brush.linearGradient(
                        colors = gradientColors,
                        start = Offset(offset, 0f),
                        end = Offset(offset + gradientWidth, height)

                    )

                    onDrawBehind {
                        // Destination
                        with(painterStar) {
                            draw(
                                size = Size(width, width)
                            )
                        }

                        // Source
                        drawRect(
                            brush = brush,
                            blendMode = BlendMode.SrcIn
                        )
                    }
                }
        )

        Text("Progress: $progress")
        Slider(
            value = progress,
            onValueChange = { progress = it },
            valueRange = -limit..limit
        )

        Text(text = "Animated progress: $progressAnimated")
        Box(
            modifier = Modifier
                .size(100.dp)
                .graphicsLayer {
                    compositingStrategy = CompositingStrategy.Offscreen
                }
                .drawWithCache {
                    val width = size.width
                    val height = size.height

                    val offset = width * progressAnimated
                    val gradientWidth = width

                    val brush = Brush.linearGradient(
                        colors = gradientColors,
                        start = Offset(offset, 0f),
                        end = Offset(offset + gradientWidth, height)

                    )

                    onDrawBehind {
                        // Destination
                        with(painterStar) {
                            draw(
                                size = Size(width, width)
                            )
                        }

                        // Source
                        drawRect(
                            brush = brush,
                            blendMode = BlendMode.SrcIn
                        )
                    }
                }
        )
    }
}
英文:

There are several ways to do it and you don't have to calculate tangent.

One way of doing it is

    val limit = 1.5f
val transition = rememberInfiniteTransition(label = "shimmer")
val progressAnimated by transition.animateFloat(
initialValue = -limit,
targetValue = limit,
animationSpec = infiniteRepeatable(
animation = tween(1500, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
), label = "shimmer"
)

And set brush with

val width = size.width
val height = size.height

val offset = width * progress
val gradientWidth = width
val brush = Brush.linearGradient(
colors = gradientColors,
start = Offset(offset, 0f),
end = Offset(offset + gradientWidth, height)
)

Result

在Compose中无限并可逆地动画线性渐变(刷子)。

Demo

@Preview
@Composable
private fun SingleGradientTest() {
Column(
Modifier.padding(20.dp)
) {
val painterStar = painterResource(id = R.drawable.star_foreground)
val limit = 1.5f
var progress by remember {
mutableStateOf(-limit)
}
val transition = rememberInfiniteTransition(label = "shimmer")
val progressAnimated by transition.animateFloat(
initialValue = -limit,
targetValue = limit,
animationSpec = infiniteRepeatable(
animation = tween(1500, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
), label = "shimmer"
)
Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
.drawWithCache {
val width = size.width
val height = size.height
val offset = width * progress
val gradientWidth = width
val brush = Brush.linearGradient(
colors = gradientColors,
start = Offset(offset, 0f),
end = Offset(offset + gradientWidth, height)
)
onDrawBehind {
drawRect(
brush = brush,
blendMode = BlendMode.SrcIn
)
}
}
)
Box(
modifier = Modifier
.size(100.dp)
.graphicsLayer {
compositingStrategy = CompositingStrategy.Offscreen
}
.drawWithCache {
val width = size.width
val height = size.height
val offset = width * progress
val gradientWidth = width
val brush = Brush.linearGradient(
colors = gradientColors,
start = Offset(offset, 0f),
end = Offset(offset + gradientWidth, height)
)
onDrawBehind {
// Destination
with(painterStar) {
draw(
size = Size(width, width)
)
}
// Source
drawRect(
brush = brush,
blendMode = BlendMode.SrcIn
)
}
}
)
Text("Progress: $progress")
Slider(
value = progress,
onValueChange = { progress = it },
valueRange = -limit..limit
)
Text(text = "Animated progress: $progressAnimated")
Box(
modifier = Modifier
.size(100.dp)
.graphicsLayer {
compositingStrategy = CompositingStrategy.Offscreen
}
.drawWithCache {
val width = size.width
val height = size.height
val offset = width * progressAnimated
val gradientWidth = width
val brush = Brush.linearGradient(
colors = gradientColors,
start = Offset(offset, 0f),
end = Offset(offset + gradientWidth, height)
)
onDrawBehind {
// Destination
with(painterStar) {
draw(
size = Size(width, width)
)
}
// Source
drawRect(
brush = brush,
blendMode = BlendMode.SrcIn
)
}
}
)
}
}

huangapple
  • 本文由 发表于 2023年7月27日 19:08:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76779131.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定