Personalizzare un'immagine

Puoi personalizzare le immagini utilizzando le proprietà di un componibile Image (contentScale, colorFilter). Puoi anche applicare i modificatori esistenti per applicare effetti diversi al tuo Image. I modificatori possono essere utilizzati su qualsiasi composable, non solo sul composable Image, mentre contentScale e colorFilter sono parametri espliciti sul composable Image.

Scala dei contenuti

Specifica un'opzione contentScale per ritagliare o modificare il modo in cui un'immagine viene ridimensionata all'interno dei suoi limiti. Per impostazione predefinita, se non specifichi un'opzione contentScale, viene utilizzato ContentScale.Fit.

Nell'esempio seguente, l'elemento componibile Image è limitato a una dimensione di 150 dp con un bordo e lo sfondo è impostato su giallo nell'elemento componibile Image per mostrare le diverse opzioni di ContentScale nella tabella seguente.

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
)

L'impostazione di diverse opzioni di ContentScale genera output diversi. La tabella seguente ti aiuta a scegliere la modalità ContentScale corretta:

Immagine di origine La sorgente verticale, che mostra un cane. L'origine orizzontale, che mostra un cane diverso.
ContentScale Risultato - Immagine verticale: Risultato - Immagine orizzontale:
ContentScale.Fit: ridimensiona l'immagine in modo uniforme, mantenendo le proporzioni (impostazione predefinita). Se i contenuti sono più piccoli delle dimensioni, l'immagine viene ridimensionata per adattarsi ai limiti. Un ritratto di un cane scalato in modo uniforme. Un paesaggio con un cane ridimensionato in modo uniforme.
ContentScale.Crop: ritaglia l'immagine al centro nello spazio disponibile. Un'immagine verticale ritagliata per riempire una cornice quadrata, che mostra solo la parte centrale dell'immagine. Un'immagine orizzontale ritagliata per riempire una cornice quadrata, che mostra solo la parte centrale dell'immagine.
ContentScale.FillHeight: ridimensiona l'origine mantenendo le proporzioni in modo che i limiti corrispondano all'altezza della destinazione. Un'immagine verticale ridimensionata per riempire l'altezza di una cornice quadrata, che mostra l'immagine completa con lo sfondo giallo visibile a sinistra e a destra. Un'immagine orizzontale ridimensionata per riempire l'altezza di un frame quadrato, con i lati ritagliati.
ContentScale.FillWidth: scala l'origine mantenendo le proporzioni in modo che i limiti corrispondano alla larghezza della destinazione. Un'immagine verticale ridimensionata per riempire la larghezza di una cornice quadrata, con la parte superiore e quella inferiore ritagliate. Un'immagine orizzontale ridimensionata per riempire la larghezza di una cornice quadrata, che mostra l'immagine completa con lo sfondo giallo visibile in alto e in basso.
ContentScale.FillBounds: scala i contenuti verticalmente e orizzontalmente in modo non uniforme per riempire i limiti di destinazione. (Nota: questa opzione distorce le immagini se le inserisci in contenitori che non corrispondono alle proporzioni esatte dell'immagine). Un'immagine verticale distorta per riempire completamente un frame quadrato, allungando l'immagine. Un'immagine orizzontale distorta per riempire completamente un frame quadrato, allungando l'immagine.
ContentScale.Inside: ridimensiona l'origine per mantenere le proporzioni all'interno dei limiti della destinazione. Se l'origine è più piccola o uguale alla destinazione in entrambe le dimensioni, si comporta in modo simile a None. I contenuti saranno sempre contenuti entro i limiti. Se i contenuti sono più piccoli dei limiti, non verrà applicata alcuna scalabilità. Immagine di origine più grande dei limiti: Un'immagine verticale, originariamente più grande dei suoi limiti quadrati, ridotta per adattarsi mantenendo le proporzioni, con sfondo giallo sui lati. Immagine di origine più piccola dei limiti: Un'immagine verticale, originariamente più piccola dei suoi limiti quadrati, visualizzata nelle sue dimensioni originali all'interno della cornice, con uno sfondo giallo intorno. Immagine di origine più grande dei limiti: Un'immagine orizzontale, originariamente più grande dei suoi limiti quadrati, ridotta per adattarsi mantenendo le proporzioni, con sfondo giallo in alto e in basso. Immagine di origine più piccola dei limiti: Un'immagine orizzontale, originariamente più piccola dei suoi limiti quadrati, visualizzata nelle sue dimensioni originali all'interno della cornice, con uno sfondo giallo intorno.
ContentScale.None: non applica alcuna scalabilità all'origine. Se i contenuti sono più piccoli dei limiti di destinazione, non verranno ridimensionati per adattarsi all'area. Immagine di origine più grande dei limiti: Un'immagine verticale, originariamente più grande dei suoi limiti quadrati, visualizzata nelle sue dimensioni originali, con parti che si estendono oltre la parte superiore e inferiore della cornice. Immagine di origine più piccola dei limiti: Un'immagine verticale, originariamente più piccola dei suoi limiti quadrati, visualizzata nelle sue dimensioni originali all'interno della cornice, con uno sfondo giallo intorno. Immagine di origine più grande dei limiti: Un'immagine orizzontale, originariamente più grande dei suoi limiti quadrati, visualizzata nelle dimensioni originali, con parti che si estendono oltre i lati sinistro e destro della cornice. Immagine di origine più piccola dei limiti: Un'immagine orizzontale, originariamente più piccola dei suoi limiti quadrati, visualizzata nelle sue dimensioni originali all'interno della cornice, con uno sfondo giallo intorno.

Ritaglia un componibile Image in una forma

Per adattare un'immagine a una forma, utilizza il modificatore clip integrato. Per ritagliare un'immagine in una forma circolare, utilizza 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)
)

L'immagine di un cane ritagliata in un cerchio perfetto.
Figura 1. Ritaglio di un'immagine con CircleShape.

Per una forma con angoli arrotondati, utilizza Modifier.clip(RoundedCornerShape(16.dp)), con le dimensioni degli angoli che vuoi arrotondare:

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

Un'immagine quadrata di un cane ritagliata con angoli arrotondati.
Figura 2. Ritaglio di un'immagine con RoundedCornerShape.

Puoi anche creare la tua forma di ritaglio estendendo Shape e fornendo un Path per la forma da ritagliare:

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

Un'immagine quadrata di un cane ritagliata in una forma ovale personalizzata.
Figura 3. Ritaglio di un'immagine con una forma di percorso personalizzata.

Aggiungi un bordo a un Image componibile

Un'operazione comune consiste nel combinare Modifier.border() con Modifier.clip() per creare un bordo attorno a un'immagine:

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

Un'immagine quadrata di un cane, ritagliata in un cerchio, con un bordo giallo intorno alla forma circolare.
Figura 4. Un'immagine ritagliata con un bordo intorno.

Per creare un bordo con gradiente, puoi utilizzare l'API Brush per disegnare un bordo con gradiente arcobaleno attorno all'immagine:

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

Un'immagine circolare di un cane con un bordo sfumato arcobaleno attorno alla forma circolare.
Figura 5. Bordo circolare con gradiente arcobaleno.

Imposta proporzioni personalizzate

Per trasformare un'immagine in proporzioni personalizzate, utilizza Modifier.aspectRatio(16f/9f) per fornire proporzioni personalizzate per un'immagine (o qualsiasi elemento componibile).

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

Un'immagine quadrata di un cane, trasformata in proporzioni 16:9, che la rendono più larga e più corta.
Figura 6. Utilizzo di Modifier.aspectRatio(16f/9f) su un Image.

Filtro colore: trasforma i colori dei pixel dell'immagine

Il composable Image ha un parametro colorFilter che può modificare l'output dei singoli pixel dell'immagine.

Immagini con tinta

L'utilizzo di ColorFilter.tint(color, blendMode) applica una modalità di fusione con il colore specificato al composable Image. ColorFilter.tint(color, blendMode) utilizza BlendMode.SrcIn per colorare i contenuti, il che significa che il colore fornito viene mostrato dove l'immagine viene visualizzata sullo schermo. Questo è utile per le icone e i vettori che devono essere tematizzati in modo diverso.

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

Un'immagine di un autobus con una tinta gialla applicata.
Figura 7. ColorFilter.tint applicato con BlendMode.SrcIn.

Altri BlendMode producono effetti diversi. Ad esempio, l'impostazione di BlendMode.Darken con un Color.Green su un'immagine produce il seguente risultato:

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

Un cane con una tinta verde applicata utilizzando BlendMode.Darken, che genera tonalità di verde più scure.
Figura 8. Color.Green tint con BlendMode.Darken.

Per ulteriori informazioni sulle diverse modalità di fusione disponibili, consulta la documentazione di riferimento di BlendMode.

Applica un filtro Image con matrice di colori

Trasforma l'immagine utilizzando l'opzione della matrice di colori ColorFilter. Ad esempio, per applicare un filtro in bianco e nero alle tue immagini, puoi utilizzare ColorMatrix e impostare la saturazione su 0f.

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

Un cane con un filtro in bianco e nero applicato, che rimuove tutta la saturazione del colore.
Figura 9. Matrice colore con saturazione 0 (immagine in bianco e nero).

Regola il contrasto o la luminosità di un componibile Image

Per modificare il contrasto e la luminosità di un'immagine, puoi utilizzare ColorMatrix per modificare i valori:

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

Un cane con luminosità e contrasto aumentati, che lo rendono più vivido.
Figura 10. Luminosità e contrasto dell'immagine regolati utilizzando ColorMatrix.

Inverti i colori di un componibile Image

Per invertire i colori di un'immagine, imposta ColorMatrix in modo da invertire i colori:

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

Un cane con l'inversione dei colori, che mostra un effetto simile a un negativo.
Figura 11. Inverti i colori sull'immagine.

Sfoca un componibile Image

Per sfocare un'immagine, utilizza Modifier.blur(), fornendo radiusX e radiusY, che specificano il raggio di sfocatura rispettivamente in direzione orizzontale e verticale.

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

Un cane con un forte effetto di sfocatura applicato, che lo rende indistinto e fuori fuoco.
Figura 12. BlurEffect applicata a un'immagine.

Quando sfumi Images, ti consigliamo di utilizzare BlurredEdgeTreatment(Shape), anziché BlurredEdgeTreatment.Unbounded, poiché quest'ultimo viene utilizzato per la sfocatura di rendering arbitrari che dovrebbero essere visualizzati al di fuori dei limiti dei contenuti originali. Per le immagini, è probabile che non vengano visualizzate al di fuori dei limiti dei contenuti, mentre la sfocatura di un rettangolo arrotondato potrebbe richiedere questa distinzione.

Ad esempio, se impostiamo BlurredEdgeTreatment su Unbounded nell'immagine precedente, i bordi dell'immagine appaiono sfocati anziché nitidi:

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

Un'immagine sfocata di un cane, in cui la sfocatura si estende oltre i confini dell'immagine originale, rendendo i bordi sfocati.
Figura 13. BlurEdgeTreatment.Unbounded.