如何为 Android Jetpack Compose Column 或 Row 添加渐隐边缘效果?

And*_*rew 5 android kotlin android-jetpack android-jetpack-compose

我需要实现具有顶部渐隐边缘效果的 LazyColumn。在 Android 上,我对 ListView 或 RecyclerView使用淡入淡出渐变,但找不到 Jetpack Compose 的任何解决方案!

在此处输入图片说明

我试图修改画布:

@Composable
fun Screen() {
    Box(
        Modifier
            .fillMaxWidth()
            .background(color = Color.Yellow)
    ) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .drawWithContent {
                    val colors = listOf(Color.Transparent, Color.Black)
                    drawContent()
                    drawRect(
                        brush = Brush.verticalGradient(colors),
                        blendMode = BlendMode.DstIn
                    )
                }
        ) {
            itemsIndexed((1..1000).toList()) { item, index ->
                Text(
                    text = "Item $item: $index value",
                    modifier = Modifier.padding(12.dp),
                    color = Color.Red,
                    fontSize = 24.sp
                )
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但有错误的结果:

在此处输入图片说明

nh7*_*nh7 20

在 Compose 1.4.0-alpha02 中引入了 CompositingStrategy。这意味着不再需要使用.graphicsLayer { alpha = 0.99f }hack。相反,您可以使用.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen).

这是一个可定制的淡入淡出边缘修改器:

fun Modifier.fadingEdge(brush: Brush) = this
    .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
    .drawWithContent {
        drawContent()
        drawRect(brush = brush, blendMode = BlendMode.DstIn)
    }
Run Code Online (Sandbox Code Playgroud)

一些例子:

@Composable
fun FadingEdgeExamples() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceEvenly,
        modifier = Modifier.fillMaxSize().background(Color.White)
    ) {

        val topFade = Brush.verticalGradient(0f to Color.Transparent, 0.3f to Color.Red)
        Box(modifier = Modifier.fadingEdge(topFade).background(Color.Blue).size(100.dp))

        val topBottomFade = Brush.verticalGradient(0f to Color.Transparent, 0.3f to Color.Red, 0.7f to Color.Red, 1f to Color.Transparent)
        Box(modifier = Modifier.fadingEdge(topBottomFade).background(Color.Blue).size(100.dp))

        val leftRightFade = Brush.horizontalGradient(0f to Color.Transparent, 0.1f to Color.Red, 0.9f to Color.Red, 1f to Color.Transparent)
        Box(modifier = Modifier.fadingEdge(leftRightFade).background(Color.Blue).size(100.dp))

        val radialFade = Brush.radialGradient(0f to Color.Red, 0.5f to Color.Transparent)
        Box(modifier = Modifier.fadingEdge(radialFade).background(Color.Blue).size(100.dp))

    }
}
Run Code Online (Sandbox Code Playgroud)

注意:指定渐变颜色时,Color.Transparent 定义淡入淡出发生的位置,任何其他颜色(在本例中为 Color.Red,无论您选择哪一种颜色)定义内容。

输出: 例子


Ale*_*ber 11

解决问题的快速技巧:添加.graphicsLayer { alpha = 0.99f }到您的修改器

默认情况下,出于性能原因,Jetpack Compose 会禁用 alpha 合成(如此处所述请参阅“自定义修改器”部分)。如果没有 Alpha 合成,影响透明度的混合模式(例如DstIn)不会达到预期的效果。目前最好的解决方法是添加到;.graphicsLayer { alpha = 0.99F }上的修饰符 LazyColumn这迫使 Jetpack Compose 通过使LazyColumn难以察觉的透明来启用 Alpha 合成。

经过此更改,您的代码如下所示:

@Composable
fun Screen() {
    Box(
        Modifier
            .fillMaxWidth()
            .background(color = Color.Yellow)
    ) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                // Workaround to enable alpha compositing
                .graphicsLayer { alpha = 0.99F }
                .drawWithContent {
                    val colors = listOf(Color.Transparent, Color.Black)
                    drawContent()
                    drawRect(
                        brush = Brush.verticalGradient(colors),
                        blendMode = BlendMode.DstIn
                    )
                }
        ) {
            itemsIndexed((1..1000).toList()) { item, index ->
                Text(
                    text = "Item $item: $index value",
                    modifier = Modifier.padding(12.dp),
                    color = Color.Red,
                    fontSize = 24.sp
                )
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

产生正确的结果


小智 9

您可以做的是将 放在Spacer列表顶部,并在该框上绘制渐变。使框变小,以便列表中只有一小部分具有覆盖层。使颜色与屏幕背景相同,看起来内容会褪色。

val screenBackgroundColor = MaterialTheme.colors.background

    Box(Modifier.fillMaxSize()) {

        LazyColumn(Modifier.fillMaxSize()) {
            //your items
        }

        //Gradient overlay
        Spacer(
            Modifier
                .fillMaxWidth()
                .height(32.dp)
                .background(
                    brush = Brush.verticalGradient(
                        colors = listOf(
                            Color.Transparent,
                            screenBackgroundColor
                        )
                    )
                )
                //.align(Alignment) to control the position of the overlay
        )
    }
Run Code Online (Sandbox Code Playgroud)

它看起来是这样的:

截屏

但是,这似乎并不完全符合您的要求,因为您似乎希望实际的列表内容淡出。我不知道如何将 analpha仅应用于视图的一部分。也许尝试深入.alpha研究来源来找出答案。