https://kotlinlang.org logo
#compose
Title
# compose
p

Piotr Prus

03/17/2023, 2:57 PM
Is there any possibility to add an alpha to a lazyRow component, so for example 30% of width will have some level of transparency, and that will change dynamically on user scroll? I have tried modifier.background, adding a box with alpha on top of the lazyRow, but this things do not modify the child views of Row. These are additional composables that render in background or in front. Picture in thread 🧵
image.png
I do think the only way to do this is using new RenderEffect API, but I have no idea how to use it in compose. Anyone has any example?
e

ephemient

03/17/2023, 3:41 PM
no need for render effects
Copy code
Modifier
    .drawWithCache {
        val brush = Brush.horizontalGradient(
            0f to Color.Transparent,
            0.35f to Color.Black,
            0.65f to Color.Black,
            1f to Color.Transparent,
        )
        onDrawWithContent {
            drawContent()
            drawRect(brush = brush, blendMode = BlendMode.DstIn)
        }
    }
p

Piotr Prus

03/17/2023, 3:52 PM
Thanks for reply! As I understand this snippet, you are drawing a RECT on top of a Row with black and transparent colors. This will not add a dynamic alpha to my child items as presented on the screen
e

ephemient

03/17/2023, 3:52 PM
DstIn will discard the colors in the gradient and only multiply the alpha through
p

Piotr Prus

03/17/2023, 3:54 PM
This is the effect of a snippet:
a

Albert Chang

03/17/2023, 4:06 PM
You also need to add
.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
(or
.graphicsLayer(alpha = 0.99f)
if you are using stable version) before
.drawWithCache
.
e

ephemient

03/17/2023, 4:13 PM
yes, without being composited separately, the alpha multiply applies all the way through
if you wanted to use a RenderEffect, you could
Copy code
val shader = remember {
    RuntimeShader(
        """
        uniform shader image;
        uniform float width;
        half4 main(vec2 coords) {
            float alpha = saturate((0.5 - abs(coords.x / width - 0.5)) / 0.35);
            half4 color = image.eval(coords);
            return half4(color.rgb, color.a * alpha);
        }
        """.trimIndent()
    )
}
var width by remember { mutableStateOf(0) }
Modifier
    .onSizeChanged { width = it.width }
    .graphicsLayer {
        shader.setFloatUniform("width", width.toFloat())
        renderEffect = RenderEffect.createRuntimeShaderEffect(shader, "image").asComposeRenderEffect()
    }
but RuntimeShader is Android 13+ and it really doesn't seem worthwhile to choose to go down that path
p

Piotr Prus

03/17/2023, 9:10 PM
Thank you so much. I added the
.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
and it works!! 🎉
18 Views