【问题标题】:How to add fading edge effect to Android Jetpack Compose Column or Row?如何为 Android Jetpack Compose Column 或 Row 添加淡入淡出的边缘效果?
【发布时间】:2022-03-26 23:13:29
【问题描述】:

我需要实现带有顶部褪色边缘效果的 LazyColumn。在 Android 上,我使用 fade gradient for ListView or 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
                )
            }
        }
    }
}

但是有错误的结果:

【问题讨论】:

标签: android kotlin android-jetpack android-jetpack-compose


【解决方案1】:

解决问题的快速技巧:.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
                )
            }
        }
    }
}

产生正确的结果

【讨论】:

    【解决方案2】:

    只需向正确的方向轻推。这段代码的作用是在 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)
            ) {
    
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以做的是在列表顶部放置一个Spacer,并在该框上绘制一个渐变。使 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 的来源以找出答案。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多