自定义图像

可以使用 Image 可组合对象上的属性(contentScalecolorFilter)来自定义图像。您还可以应用现有的 Modifiers 来对您的 Image 应用不同的效果。修饰符可用于**任何可组合对象**,而不仅仅是 Image 可组合对象,而 contentScalecolorFilterImage 可组合对象上的显式参数。

内容缩放

指定 contentScale 选项来裁剪或更改图像在其边界内缩放的方式。默认情况下,如果您未指定 contentScale 选项,则将使用 ContentScale.Fit

在下面的示例中,Image 可组合对象被限制为 150dp 大小,并带有边框,并且在 Image 可组合对象上将背景设置为黄色,以展示下表中不同的 ContentScale 选项。

val imageModifier = Modifier
    .size(150.dp)
    .border(BorderStroke(1.dp, Color.Black))
    .background(Color.Yellow)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Fit,
    modifier = imageModifier
)

设置不同的 ContentScale 选项将导致不同的输出。下面是一个表格,可以帮助您选择所需的正确 ContentScale 模式

源图像 Portrait source image Source image landscape
ContentScale 结果 - 纵向图像 结果 - 横向图像
ContentScale.Fit:统一缩放图像,保持纵横比(默认)。如果内容小于大小,则图像将放大以适合边界。 ContentScale.Fit portrait ContentScale.Fit landscape
ContentScale.Crop:将图像居中裁剪到可用空间中。 ContentScale.Crop portrait ContentScale.Crop landscape
ContentScale.FillHeight:缩放源图像以保持纵横比,使边界与目标高度匹配。 ContentScale.FillHeight portrait ContentScale.FillHeight landscape
ContentScale.FillWidth:缩放源图像以保持纵横比,使边界与目标宽度匹配。 ContentScale.FillWidth portrait ContentScale.FillWidth landscape
ContentScale.FillBounds:垂直和水平**非均匀**地缩放内容以填充目标边界。(注意:如果您将图像放置在与图像精确比例不匹配的容器中,这将导致图像失真) ContentScale.FillBounds portrait ContentScale.FillBounds landscape
ContentScale.Inside:缩放源图像以在目标边界内保持纵横比。如果源图像在两个维度上都小于或等于目标图像,则其行为类似于 `None`。内容将始终包含在边界内。如果内容小于边界,则不会应用缩放。 源图像大于边界:ContentScale.Inside 纵向,源图像大于边界 源图像小于边界:ContentScale.Inside 纵向,源图像小于边界 源图像大于边界:ContentScale.Inside 横向,源图像大于边界 源图像小于边界:ContentScale.Inside 横向,源图像小于边界
ContentScale.None:不对源图像应用任何缩放。如果内容小于目标边界,则不会将其放大以适合该区域。 源图像大于边界:ContentScale.None 纵向,源图像大于边界 源图像小于边界:ContentScale.None 纵向,源图像小于边界 源图像大于边界:ContentScale.None 横向,源图像大于边界 源图像小于边界:ContentScale.None 横向,源图像小于边界

Image 可组合对象裁剪成形状

要使图像适合某个形状,请使用内置的 clip 修饰符。要将图像裁剪成圆形,请使用 Modifier.clip(CircleShape)

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(CircleShape)
)

Clipping an image with CircleShape
图 1:使用 CircleShape 裁剪图像

圆角形状 - 使用 Modifier.clip(RoundedCornerShape(16.dp)) 和您想要圆角的大小

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(RoundedCornerShape(16.dp))
)

Clipping an image with RoundedCornerShape
图 2:使用 RoundedCornerShape 裁剪图像

您还可以通过扩展 Shape 并为要裁剪的形状提供 Path 来创建自己的裁剪形状

class SquashedOval : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        val path = Path().apply {
            // We create an Oval that starts at ¼ of the width, and ends at ¾ of the width of the container.
            addOval(
                Rect(
                    left = size.width / 4f,
                    top = 0f,
                    right = size.width * 3 / 4f,
                    bottom = size.height
                )
            )
        }
        return Outline.Generic(path = path)
    }
}

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(SquashedOval())
)

Clipping an image with custom path shape
图 3:使用自定义路径形状裁剪图像

Image 可组合对象添加边框

一个常见的操作是将 Modifier.border()Modifier.clip() 组合,以在图像周围创建边框

val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, Color.Yellow),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

Clip an image and provide a border around it
图 4:裁剪图像并在其周围提供边框

如果您希望创建渐变边框,则可以使用 Brush API 在图像周围绘制彩虹渐变边框

val rainbowColorsBrush = remember {
    Brush.sweepGradient(
        listOf(
            Color(0xFF9575CD),
            Color(0xFFBA68C8),
            Color(0xFFE57373),
            Color(0xFFFFB74D),
            Color(0xFFFFF176),
            Color(0xFFAED581),
            Color(0xFF4DD0E1),
            Color(0xFF9575CD)
        )
    )
}
val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, rainbowColorsBrush),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

Rainbow gradient circle border
图 5:彩虹渐变圆形边框

设置自定义纵横比

要将图像转换为自定义纵横比,请使用 Modifier.aspectRatio(16f/9f) 为图像(或任何可组合对象)提供自定义比例。

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    modifier = Modifier.aspectRatio(16f / 9f)
)

Using Modifier.aspectRatio(16f/9f) on Image
图 6:在 Image 上使用 Modifier.aspectRatio(16f/9f)

颜色滤镜 - 转换图像的像素颜色

Image 可组合对象具有一个 colorFilter 参数,可以更改图像的各个像素的输出。

给图像着色

使用 ColorFilter.tint(color, blendMode) 将混合模式与给定颜色一起应用到您的 Image 可组合对象上。 ColorFilter.tint(color, blendMode) 使用 BlendMode.SrcIn 对内容进行着色,这意味着将显示提供的颜色,图像在屏幕上显示的位置。这对于需要以不同方式设置主题的图标和矢量很有用。

Image(
    painter = painterResource(id = R.drawable.baseline_directions_bus_24),
    contentDescription = stringResource(id = R.string.bus_content_description),
    colorFilter = ColorFilter.tint(Color.Yellow)
)

ColorFilter.tint applied with BlendMode.SrcIn
图 7:使用 BlendMode.SrcIn 应用 ColorFilter.tint

其他 BlendMode 会产生不同的效果。例如,在图像上设置 BlendMode.DarkenColor.Green 会产生以下结果

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.tint(Color.Green, blendMode = BlendMode.Darken)
)

Color.Green tint with BlendMode.Darken
图 8:使用 BlendMode.Darken 的 Color.Green 着色

有关可用不同混合模式的更多信息,请参阅 混合模式参考文档

使用颜色矩阵应用 Image 滤镜

使用颜色矩阵 ColorFilter 选项转换您的图像。例如,要将黑白滤镜应用到您的图像,您可以使用 ColorMatrix 并将饱和度设置为 0f

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })
)

Color Matrix with saturation 0 (black and white image)
图 9:饱和度为 0 的颜色矩阵(黑白图像)

调整 Image 可组合对象的对比度或亮度

要更改图像的对比度和亮度,您可以使用 ColorMatrix 来更改值

val contrast = 2f // 0f..10f (1 should be default)
val brightness = -180f // -255f..255f (0 should be default)
val colorMatrix = floatArrayOf(
    contrast, 0f, 0f, 0f, brightness,
    0f, contrast, 0f, 0f, brightness,
    0f, 0f, contrast, 0f, brightness,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

Adjusted image brightness and contrast using ColorMatrix
图 10:使用 ColorMatrix 调整图像亮度和对比度

反转 Image 可组合对象的颜色

要反转图像的颜色,请将 ColorMatrix 设置为反转颜色

val colorMatrix = floatArrayOf(
    -1f, 0f, 0f, 0f, 255f,
    0f, -1f, 0f, 0f, 255f,
    0f, 0f, -1f, 0f, 255f,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

Inverted colors on image
图 11:图像上的颜色反转

模糊 Image 可组合对象

要模糊图像,请使用 Modifier.blur(),并提供 radiusXradiusY,分别指定水平和垂直方向上的模糊半径。

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp))
        )
)

BlurEffect applied to image
图 12:应用于图像的 BlurEffect

在模糊 Images 时,建议使用 BlurredEdgeTreatment(Shape),而不是 BlurredEdgeTreatment.Unbounded,因为后者用于模糊预计在原始内容边界之外呈现的任意渲染。对于图像,它们不太可能在内容边界之外呈现;而模糊圆角矩形可能需要这种区别。

例如,如果我们在上面的图像上将 BlurredEdgeTreatment 设置为 Unbounded,则图像的边缘会显示为模糊而不是清晰

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment.Unbounded
        )
        .clip(RoundedCornerShape(8.dp))
)

BlurEdgeTreatment.Unbounded
图 13:BlurEdgeTreatment.Unbounded