Personalizar uma imagem

É possível personalizar imagens usando propriedades em um elemento combinável Image (contentScale, colorFilter). Também é possível aplicar modificadores para aplicar efeitos diferentes à Image. Os modificadores podem ser usados em qualquer elemento combinável, não apenas na Image combinável, enquanto contentScale e colorFilter são parâmetros explícitos nela.Image

Escala de conteúdo

Especifique uma opção contentScale para cortar ou mudar o dimensionamento de uma imagem dentro dos limites dela. Por padrão, se você não especificar uma opção contentScale, ContentScale.Fit será usado.

No exemplo a seguir, o elemento combinável Image é restrito a um tamanho de 150 dp com uma borda, e o plano de fundo é definido como amarelo no elemento combinável Image para mostrar as diferentes opções ContentScale na tabela abaixo.

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
)

Definir opções ContentScale diferentes resulta em saídas diferentes. A tabela a seguir ajuda você a escolher o modo ContentScale correto:

Imagem de origem A origem do retrato, que mostra um cachorro. A origem da paisagem, que mostra um cachorro diferente.
ContentScale Resultado – Imagem em modo retrato: Resultado – Imagem em modo paisagem:
ContentScale.Fit: redimensiona a imagem de maneira uniforme, mantendo a proporção (padrão). Se o conteúdo for menor que o tamanho, a imagem vai ser dimensionada na vertical para se ajustar aos limites. Um retrato de cachorro dimensionado de maneira uniforme. Uma paisagem com um cachorro dimensionada de maneira uniforme.
ContentScale.Crop: corta a imagem no meio para se ajustar ao espaço disponível. Uma imagem de retrato cortada para preencher um frame quadrado, mostrando apenas a parte central da imagem. Uma imagem em modo paisagem cortada para preencher um frame quadrado, mostrando apenas a parte central da imagem.
ContentScale.FillHeight: redimensiona a imagem de origem mantendo a proporção para que os limites correspondam à altura do destino. Uma imagem em modo retrato dimensionada para preencher a altura de um quadro quadrado, mostrando a imagem completa com fundo amarelo visível à esquerda e à direita. Uma imagem em modo paisagem dimensionada para preencher a altura de um frame quadrado, com os lados cortados.
ContentScale.FillWidth: redimensiona a imagem de origem mantendo a proporção para que os limites correspondam à largura do destino. Uma imagem retrato dimensionada para preencher a largura de uma moldura quadrada, com a parte de cima e de baixo cortadas. Uma imagem de paisagem dimensionada para preencher a largura de um quadro quadrado, mostrando a imagem completa com o plano de fundo amarelo visível na parte de cima e de baixo.
ContentScale.FillBounds: redimensiona o conteúdo na vertical e na horizontal de maneira não uniforme para preencher os limites de destino. Observação: isso vai distorcer as imagens se você as colocar em contêineres que não correspondam à proporção exata delas. Uma imagem de retrato distorcida para preencher completamente um frame quadrado, esticando a imagem. Uma imagem de paisagem distorcida para preencher completamente um frame quadrado, esticando a imagem.
ContentScale.Inside: redimensiona a imagem de origem para manter a proporção dentro dos limites do destino. Se ela for menor ou igual ao destino nas duas dimensões, vai se comportar de maneira semelhante a None. O conteúdo sempre vai estar dentro dos limites. Se o conteúdo for menor que os limites, a imagem não vai ser redimensionada. Imagem de origem maior que os limites: Uma imagem retrato, originalmente maior do que os limites quadrados, reduzida para caber mantendo a proporção, mostrando fundo amarelo nas laterais. Imagem de origem menor que os limites: Uma imagem retrato, originalmente menor que os limites quadrados, exibida no tamanho original dentro do frame, mostrando um plano de fundo amarelo ao redor dela. Imagem de origem maior que os limites: Uma imagem de paisagem, originalmente maior do que os limites quadrados, reduzida para caber, mantendo a proporção e mostrando um fundo amarelo na parte de cima e de baixo. Imagem de origem menor que os limites: Uma imagem em paisagem, originalmente menor que os limites quadrados, exibida no tamanho original dentro do frame, mostrando um plano de fundo amarelo ao redor dela.
ContentScale.None: não redimensiona a imagem de origem. Se o conteúdo for menor que os limites de destino, ele não vai ser redimensionado para se ajustar à área. Imagem de origem maior que os limites: Uma imagem de retrato, originalmente maior que os limites quadrados, exibida no tamanho original, com partes que se estendem além da parte superior e inferior do frame. Imagem de origem menor que os limites: Uma imagem retrato, originalmente menor que os limites quadrados, exibida no tamanho original dentro do frame, mostrando um plano de fundo amarelo ao redor dela. Imagem de origem maior que os limites: Uma imagem de paisagem, originalmente maior do que os limites quadrados, exibida no tamanho original, com partes que se estendem além da esquerda e da direita do frame. Imagem de origem menor que os limites: Uma imagem em paisagem, originalmente menor que os limites quadrados, exibida no tamanho original dentro do frame, mostrando um plano de fundo amarelo ao redor dela.

Cortar um elemento combinável Image em uma forma

Para que uma imagem se encaixe em uma forma, use o modificador clip integrado. Para cortar uma imagem em formato de círculo, use 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)
)

Uma imagem de um cachorro cortada em um círculo perfeito.
Figura 1. Cortar uma imagem com CircleShape.

Para uma forma de canto arredondado, use Modifier.clip(RoundedCornerShape(16.dp) com o tamanho dos cantos que você quer arredondar:

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

Uma imagem quadrada de um cachorro cortada com cantos arredondados.
Figura 2. Cortar uma imagem com RoundedCornerShape.

Também é possível criar sua própria forma de recorte estendendo Shape e fornecendo um Path para que a forma seja cortada:

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

Uma imagem quadrada de um cachorro cortada em uma forma oval personalizada.
Figura 3. Cortar uma imagem com forma de caminho personalizada.

Adicionar uma borda a um elemento combinável Image

Uma operação comum é combinar Modifier.border() com Modifier.clip() para criar uma borda ao redor de uma imagem:

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

Uma imagem quadrada de um cachorro, cortada em um círculo, com uma borda amarela ao redor da forma circular.
Figura 4. Uma imagem cortada com uma borda ao redor.

Para criar uma borda de gradiente, use a API Brush para desenhar uma borda de gradiente do arco-íris na imagem:

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

Uma imagem circular de um cachorro com uma borda de gradiente de arco-íris ao redor da forma circular.
Figura 5. Borda do círculo com gradiente de arco-íris.

Definir uma proporção personalizada

Para transformar uma imagem em uma proporção personalizada, use Modifier.aspectRatio(16f/9f) para fornecer uma proporção personalizada para uma imagem (ou qualquer elemento combinável).

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

Uma imagem quadrada de um cachorro, transformada em uma proporção de 16:9, tornando-a mais larga e mais curta.
Figura 6. Usar o Modifier.aspectRatio(16f/9f) em um Image.

Filtro de cores: transformar as cores de pixel da imagem

O elemento combinável Image tem um parâmetro colorFilter que pode mudar a saída de pixels individuais da imagem.

Colorir imagens

O uso de ColorFilter.tint(color, blendMode) aplica um modo de combinação com a cor especificada na Image combinável. ColorFilter.tint(color, blendMode) usa BlendMode.SrcIn para colorir o conteúdo, o que significa que a cor fornecida é mostrada na área em que a imagem é exibida na tela. Isso é útil para ícones e veículos que precisam ter um tema diferente.

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

Imagem de um ônibus com um tom amarelo aplicado.
Figura 7. ColorFilter.tint aplicado com BlendMode.SrcIn.

Outros BlendModes resultam em efeitos diferentes. Por exemplo, definir BlendMode.Darken com uma Color.Green em uma imagem produz o seguinte resultado:

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

Um cachorro com uma tonalidade verde aplicada usando BlendMode.Darken, resultando em tons de verde mais escuros.
Figura 8. Color.Green tint com BlendMode.Darken.

Consulte a documentação de referência do BlendMode para mais informações sobre os diferentes modos de combinação disponíveis.

Aplicar um filtro Image com matriz de cores

Transforme sua imagem usando a opção de matriz de cor ColorFilter. Por exemplo, para aplicar um filtro preto e branco nas imagens, use a ColorMatrix e defina a saturação como 0f.

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

Um cachorro com um filtro preto e branco aplicado, removendo toda a saturação de cor.
Figura 9. Matriz de cores com saturação 0 (imagem em preto e branco).

Ajustar o contraste ou o brilho de um elemento combinável Image

Para mudar o contraste e o brilho de uma imagem, use a ColorMatrix para mudar os valores:

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

Um cachorro com brilho e contraste aumentados, o que o faz parecer mais vívido.
Figura 10. Ajuste de brilho e contraste de imagem usando ColorMatrix.

Inverter cores de um elemento combinável Image

Para inverter as cores de uma imagem, defina a ColorMatrix para inverter as cores:

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

Um cachorro com as cores invertidas, mostrando um efeito negativo.
Figura 11. Cores invertidas na imagem.

Desfocar um elemento combinável Image

Para desfocar uma imagem, use Modifier.blur(), fornecendo radiusX e radiusY, que especificam o raio de desfoque na direção horizontal e vertical, respectivamente.

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

Um cachorro com um forte efeito de desfoque aplicado, fazendo com que ele pareça indistinto e fora de foco.
Figura 12. BlurEffect aplicado a uma imagem.

Ao desfocar Images, é recomendável usar BlurredEdgeTreatment(Shape), em vez de BlurredEdgeTreatment.Unbounded, já que o último é usado para desfocar renderizações arbitrárias que precisam ser renderizadas fora dos limites do conteúdo original. Para imagens, é provável que elas não sejam renderizadas fora dos limites do conteúdo. O desfoque de um retângulo arredondado pode exigir essa distinção.

Por exemplo, se definirmos o BlurredEdgeTreatment como Unbounded na imagem anterior, as bordas da imagem vão aparecer desfocadas em vez de nítidas:

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

Uma imagem desfocada de um cachorro, em que o desfoque se estende além dos limites da imagem original, deixando as bordas borradas.
Figura 13. BlurEdgeTreatment.Unbounded.