Jetpack Compose 中的图像渐变

Gradient over image in Jetpack Compose

这是我的组件:

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

这是它的样子:

我想在 ImageText 后面显示深色渐变,以便文本易于阅读。我想我必须使用 LinearGradientRadialGradient,但由于缺少文档,我无法使用它。

编辑:This 是我尝试使用 Jetpack Compose 进行的操作。

哇,那个花了几个小时 ;)

您可以将 Modifier.backgroundVerticalGradient 一起使用。我使用 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,
                )
            }
        }
    }
}

这是我的样本的样子:

对于 1.0.0,您可以使用类似的东西:

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 modifier and the 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)
          }
      }
  )

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

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

输出

直截了当:

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