【问题标题】:Gradient over image in Jetpack ComposeJetpack Compose 中的图像渐变
【发布时间】:2020-09-13 14:06:55
【问题描述】:

这是我的组件:

@Composable
fun Cover(
    name: String,
    imageRes: Int,
    modifier: Modifier = Modifier.padding(16.dp, 8.dp)
) {
    Box(modifier) {
        Card(
            shape = RoundedCornerShape(4.dp),
            backgroundColor = MaterialTheme.colors.secondary,
            elevation = 4.dp
        ) {
            Stack {
                Image(
                    imageResource(imageRes),
                    modifier = Modifier
                        .gravity(Alignment.Center)
                        .aspectRatio(2f),
                    contentScale = ContentScale.Crop,
                )

                Text(
                    text = name,
                    modifier = Modifier
                        .gravity(Alignment.BottomStart)
                        .padding(8.dp),
                    style = MaterialTheme.typography.h6
                )
            }
        }
    }
}

看起来是这样的:

我想在Image 和Text 后面显示一个深色渐变,以便文本易于阅读。我想我必须使用LinearGradient 或RadialGradient,但由于缺乏文档,我无法做到。

编辑:This 是我想要做的,但使用 Jetpack Compose。

【问题讨论】:

  • 使用Modifier.drawBackground() 传递LinearGradient 或RadialGradient
  • @MohammadSianaki 该函数现在被称为 Modifier.background()

标签: android gradient android-jetpack-compose


【解决方案1】:

使用1.0.0(使用1.0.0-beta08 测试),您可以使用类似:

var sizeImage by remember { mutableStateOf(IntSize.Zero) }

val gradient = Brush.verticalGradient(
    colors = listOf(Color.Transparent, Color.Black),
    startY = sizeImage.height.toFloat()/3,  // 1/3
    endY = sizeImage.height.toFloat()
)

Box(){
    Image(painter = painterResource(id = R.drawable.banner),
        contentDescription = "",
    modifier = Modifier.onGloballyPositioned {
        sizeImage = it.size
    })
    Box(modifier = Modifier.matchParentSize().background(gradient))
}

原文:

之后:

您还可以使用.drawWithCache 修饰符和onDrawWithContent 将渐变应用于Image(),允许开发人员在布局内容之前或之后进行绘制。

  Image(painter = painterResource(id = R.drawable.conero),
      contentDescription = "",
      modifier = Modifier.drawWithCache {
          val gradient = Brush.verticalGradient(
              colors = listOf(Color.Transparent, Color.Black),
              startY = size.height/3,
              endY = size.height
          )
          onDrawWithContent {
              drawContent()
              drawRect(gradient,blendMode = BlendMode.Multiply)
          }
      }
  )

【讨论】:

  • 实际上并没有按预期工作。它只会使图像更暗。也许我做错了什么
  • 另外,我不明白startX、startY、endX、endY 参数的期望。为什么endY 有size.width?不应该是size.height吗?
  • @Ashar7 正确。它应该是size.height(我的错,用正方形尝试了代码)。 startX、startY、endX、endY 是渐变的坐标。在上面的代码中,它们是由size = this.size 构建的。您也可以使用不同的blendMode
【解决方案2】:

哇,这花了几个小时;)

您可以将Modifier.background 与VerticalGradient 一起使用。我使用 Column 来保存修饰符并进行计算以获取图像大小,但您的解决方案可能会有所不同,您可以以不同的方式计算或存储大小,并将修饰符放在其他地方。我在代码中留下了两个 TODO,以便您可以调整渐变。

@Composable
fun Cover(
    name: String,
    imageRes: Int,
    modifier: Modifier = Modifier.padding(16.dp, 8.dp)
) {
    val density = DensityAmbient.current.density
    val width = remember { mutableStateOf(0f) }
    val height = remember { mutableStateOf(0f) }
    Box(modifier) {
        Card(
            shape = RoundedCornerShape(4.dp),
            backgroundColor = MaterialTheme.colors.secondary,
            elevation = 4.dp
        ) {
            Stack {
                Image(
                    imageResource(imageRes),
                    modifier = Modifier
                        .gravity(Alignment.Center)
                        .aspectRatio(2f)
                        .onPositioned {
                            width.value = it.size.width / density
                            height.value = it.size.height / density
                        },
                    contentScale = ContentScale.Crop,
                )
                Column(
                    Modifier.size(width.value.dp, height.value.dp)
                        .background(
                            VerticalGradient(
                                listOf(Color.Transparent, Color.Black),
                                0f,  // TODO: set start
                                500f,  // TODO: set end
                            )
                        )
                ) {}
                Text(
                    text = name,
                    modifier = Modifier.gravity(Alignment.BottomStart)
                        .padding(8.dp),
                    style = typography.h6,
                )
            }
        }
    }
}

这就是我的示例的样子:

【讨论】:

  • 看起来很棒!但是你为什么用500f?
  • 我尝试了几个值,发现它会因情况而异,所以我只留下了 500,这在示例中看起来不错。我相信数值和颜色都会根据图像的大小和类型而变化
【解决方案3】:

@vitor-ramos的更新答案

1.0.0-alpha09

import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.AmbientDensity
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.unit.dp
import tech.abd3lraouf.learn.compose.kombose.ui.theme.typography

@Composable
fun Cover(
    name: String,
    @DrawableRes imageRes: Int,
    modifier: Modifier = Modifier
) {
    val image = imageResource(imageRes)
    val density = AmbientDensity.current.density
    val width = remember { mutableStateOf(0f) }
    val height = remember { mutableStateOf(0f) }
    Box(
        modifier
            .padding(16.dp, 8.dp)
    ) {
        Card(
            shape = RoundedCornerShape(4.dp),
            backgroundColor = MaterialTheme.colors.secondary,
            elevation = 4.dp
        ) {
            Box {
                Image(
                    image,
                    modifier = Modifier
                        .align(Alignment.Center)
                        .aspectRatio(2f)
                        .onGloballyPositioned {
                            width.value = it.size.width / density
                            height.value = it.size.height / density
                        },
                    contentScale = ContentScale.Crop,
                )
                Column(
                    Modifier
                        .size(width.value.dp, height.value.dp)
                        .background(
                            Brush.verticalGradient(
                                listOf(Color.Transparent, Color.Black),
                                image.height * 0.6F,
                                image.height * 1F
                            )
                        )
                ) {}
                Text(
                    text = name,
                    modifier = Modifier
                        .align(Alignment.BottomStart)
                        .padding(8.dp),
                    style = typography.body2,
                    color = Color.White
                )
            }
        }
    }
}

另外,请注意渐变如何绘制其高度的控制。

输出

【讨论】:

  • 似乎 AmbientDensity 已从 Compose 中删除,无论如何我找不到任何解释,请您解释一下它是如何工作的?它是什么以及被什么取代?也可以将修改器保留在记住并在单击按钮时更改主容器的背景值?
【解决方案4】:

直截了当:

        Card(shape = RoundedCornerShape(8.dp)) {
        Box {
            Image(...)
            Text(
                text = "title",
                modifier = Modifier
                    .align(Alignment.BottomCenter)
                    .fillMaxWidth()
                    .background(Brush.verticalGradient(0F to Color.Transparent, .5F to Color.Red, 1F to Color.Red))
                    .padding(start = 8.dp, end = 8.dp, bottom = 8.dp, top = 16.dp),
                color = Color.White,
                style = MaterialTheme.typography.body1,
                textAlign = TextAlign.Start
            )
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2022-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多