如何添加渐变边缘效果到Android Jetpack组合列或行?

relj7zay  于 2022-12-02  发布在  Android
关注(0)|答案(5)|浏览(223)

我需要实现LazyColumn的顶部褪色边缘效果。在Android上我使用fade gradient for ListView or RecyclerView,但无法找到任何解决方案的Jetpack合成!

我试着修改画布:

@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
                )
            }
        }
    }
}

但结果却错了:

eeq64g8w

eeq64g8w1#

解决问题的快速黑客:.graphicsLayer { alpha = 0.99f }添加到修改器
默认情况下,Jetpack Compose出于性能原因禁用alpha合成(如here;请参阅“自定义修改器”一节)。如果没有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
                )
            }
        }
    }
}

从而产生正确的结果

brjng4g3

brjng4g32#

你可以在列表的顶部放置一个Spacer,然后在Box上绘制一个渐变。使Box变小,这样只有列表的一小部分有覆盖层。使颜色与屏幕背景相同,这样看起来内容就像是在褪色。

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
        )
    }

它的外观如下:

然而,这似乎并不是您所要求的,因为您似乎希望实际的列表内容淡出。我不知道您如何将alpha应用于视图的一部分。也许您可以尝试深入研究.alpha源代码来找出答案。

amrnrhlw

amrnrhlw3#

只需朝正确的方向稍微移动一下。这段代码所做的是在LazyColumn的顶部放置一个Box可组合对象,并使用alpha修改器进行淡入淡出。您可以再次在一个Column中创建多个Box可组合对象,以创建更平滑的效果。

@Composable
fun FadingExample() {
    Box(
        Modifier
            .fillMaxWidth()
            .requiredHeight(500.dp)) {

        LazyColumn(Modifier.fillMaxSize()) {

        }

        Box(
            Modifier
                .fillMaxWidth()
                .height(10.dp)
                .alpha(0.5f)
                .background(Color.Transparent)
                .align(Alignment.TopCenter)
        ) {

        }
    }
}
zvokhttg

zvokhttg4#

我优化了@user3872620解决方案。您只需将这几行放在LazyColumn、VerticalPager..下面,然后调整偏移/高度,通常偏移=高度

Box(
    Modifier
        .fillMaxWidth()
        .offset(y= (-10).dp)
        .height(10.dp)
        .background(brush = Brush.verticalGradient(
            colors = listOf(
                Color.Transparent,
                MaterialTheme.colors.background
            )
        ))
)

您将得到以下渲染:There is the render

yruzcnhs

yruzcnhs5#

这是使用AndroidView的FadingEdgeLazyColumn的一个非常简单的实现。在LazyColumn的顶部和底部应用渐变背景放置AndroidView

@Stable
object GradientDefaults {
    @Stable
    val Color = androidx.compose.ui.graphics.Color.Black

    @Stable
    val Height = 30.dp
}

@Stable
sealed class Gradient {
    @Immutable
    data class Top(
        val color: Color = GradientDefaults.Color,
        val height: Dp = GradientDefaults.Height,
    ) : Gradient()

    @Immutable
    data class Bottom(
        val color: Color = GradientDefaults.Color,
        val height: Dp = GradientDefaults.Height,
    ) : Gradient()
}

@Composable
fun FadingEdgeLazyColumn(
    modifier: Modifier = Modifier,
    gradients: Set<Gradient> = setOf(Gradient.Top(), Gradient.Bottom()),
    contentGap: Dp = 0.dp,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    userScrollEnabled: Boolean = true,
    content: LazyListScope.() -> Unit,
) {
    val topGradient =
        remember(gradients) { gradients.find { it is Gradient.Top } as? Gradient.Top }
    val bottomGradient =
        remember(gradients) { gradients.find { it is Gradient.Bottom } as? Gradient.Bottom }

    ConstraintLayout(modifier = modifier) {
        val (topGradientRef, lazyColumnRef, bottomGradientRef) = createRefs()

        GradientView(
            modifier = Modifier
                .constrainAs(topGradientRef) {
                    top.linkTo(parent.top)
                    width = Dimension.matchParent
                    height = Dimension.value(topGradient?.height ?: GradientDefaults.Height)
                }
                .zIndex(2f),
            colors = intArrayOf(
                (topGradient?.color ?: GradientDefaults.Color).toArgb(),
                Color.Transparent.toArgb()
            ),
            visible = topGradient != null
        )
        LazyColumn(
            modifier = Modifier
                .constrainAs(lazyColumnRef) {
                    top.linkTo(
                        anchor = topGradientRef.top,
                        margin = when (topGradient != null) {
                            true -> contentGap
                            else -> 0.dp
                        }
                    )
                    bottom.linkTo(
                        anchor = bottomGradientRef.bottom,
                        margin = when (bottomGradient != null) {
                            true -> contentGap
                            else -> 0.dp
                        }
                    )
                    width = Dimension.matchParent
                    height = Dimension.fillToConstraints
                }
                .zIndex(1f),
            state = state,
            contentPadding = contentPadding,
            reverseLayout = reverseLayout,
            verticalArrangement = verticalArrangement,
            horizontalAlignment = horizontalAlignment,
            flingBehavior = flingBehavior,
            userScrollEnabled = userScrollEnabled,
            content = content
        )
        GradientView(
            modifier = Modifier
                .constrainAs(bottomGradientRef) {
                    bottom.linkTo(parent.bottom)
                    width = Dimension.matchParent
                    height = Dimension.value(bottomGradient?.height ?: GradientDefaults.Height)
                }
                .zIndex(2f),
            colors = intArrayOf(
                Color.Transparent.toArgb(),
                (bottomGradient?.color ?: GradientDefaults.Color).toArgb(),
            ),
            visible = bottomGradient != null
        )
    }
}

@Composable
private fun GradientView(
    modifier: Modifier = Modifier,
    @Size(value = 2) colors: IntArray,
    visible: Boolean = true,
) {
    AndroidView(
        modifier = modifier,
        factory = { context ->
            val gradientBackground = GradientDrawable(
                GradientDrawable.Orientation.TOP_BOTTOM,
                colors
            ).apply {
                cornerRadius = 0f
            }
            View(context).apply {
                layoutParams = LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    LayoutParams.MATCH_PARENT
                )
                background = gradientBackground
                visibility = when (visible) {
                    true -> View.VISIBLE
                    else -> View.INVISIBLE
                }
            }
        }
    )
}

相关问题