Dostosowywanie obrazu

Obrazy możesz dostosowywać za pomocą właściwości w Image komponowalnymcontentScale (colorFilter). Możesz też zastosować istniejące modyfikatory, aby dodać różne efekty do Image. Modyfikatorów można używać w dowolnym komponencie, nie tylko w komponencie Image, natomiast contentScalecolorFilter to jawne parametry komponentu Image.

Skala treści

Określ opcję contentScale, aby przyciąć obraz lub zmienić sposób jego skalowania w ramach jego granic. Jeśli nie określisz opcji contentScale, domyślnie używana jest opcja ContentScale.Fit.

W poniższym przykładzie Image jest ograniczony do rozmiaru 150 dp z obramowaniem, a tło jest ustawione na żółte w Image, aby zaprezentować różne opcje ContentScale w tabeli poniżej.

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
)

Ustawienie różnych opcji ContentScale powoduje uzyskanie różnych wyników. W wyborze odpowiedniego trybu ContentScale pomoże Ci ta tabela:

Obraz źródłowy Źródło portretu, na którym widać psa. Źródło w formacie poziomym, na którym widać innego psa.
ContentScale Wynik – obraz w orientacji pionowej: Wynik – obraz poziomy:
ContentScale.Fit: skaluje obraz równomiernie, zachowując format obrazu (domyślnie). Jeśli treść jest mniejsza niż rozmiar, obraz jest skalowany w górę, aby dopasować się do granic. Portret psa skalowany równomiernie. Pies w krajobrazie, przeskalowany w jednolity sposób.
ContentScale.Crop: wyśrodkuj przycięty obraz w dostępnym miejscu. Zdjęcie portretowe przycięte tak, aby wypełniało kwadratową ramkę, pokazujące tylko środkową część obrazu. Obraz poziomy przycięty tak, aby wypełniał kwadratową ramkę, w której widać tylko środkową część obrazu.
ContentScale.FillHeight: skaluje źródło przy zachowaniu formatu obrazu, tak aby granice odpowiadały wysokości miejsca docelowego. Zdjęcie portretowe przeskalowane tak, aby wypełniało wysokość kwadratowej ramki. Po lewej i prawej stronie widać pełny obraz z żółtym tłem. Obraz poziomy przeskalowany tak, aby wypełniał wysokość kwadratowej ramki, z przyciętymi bokami.
ContentScale.FillWidth: Skaluj źródło, zachowując format obrazu, tak aby granice odpowiadały szerokości miejsca docelowego. Obraz w orientacji pionowej przeskalowany tak, aby wypełniał szerokość kwadratowej ramki, z przyciętą górną i dolną częścią. Obraz poziomy przeskalowany tak, aby wypełniał szerokość kwadratowej ramki. Cały obraz jest widoczny, a u góry i u dołu widać żółte tło.
ContentScale.FillBounds: skaluje treść w pionie i poziomie nierównomiernie, aby wypełnić granice miejsca docelowego. (Uwaga: powoduje to zniekształcenie obrazów, jeśli umieścisz je w kontenerach, których format nie odpowiada dokładnie formatowi obrazu). Obraz w orientacji pionowej zniekształcony tak, aby całkowicie wypełniał kwadratową ramkę, co powoduje rozciągnięcie obrazu. Obraz poziomy zniekształcony tak, aby całkowicie wypełniał kwadratową ramkę, co powoduje rozciągnięcie obrazu.
ContentScale.Inside: skaluje źródło, aby zachować współczynnik proporcji w granicach miejsca docelowego. Jeśli źródło jest mniejsze lub równe miejscu docelowemu w obu wymiarach, zachowuje się podobnie jak None. Treści zawsze będą mieścić się w granicach. Jeśli treść jest mniejsza niż granice, nie zostanie przeskalowana. Obraz źródłowy większy niż granice: Obraz w formacie pionowym, pierwotnie większy niż kwadratowe granice, został zmniejszony, aby się w nich zmieścić, przy zachowaniu współczynnika proporcji. Po bokach widać żółte tło. Obraz źródłowy mniejszy niż granice: Obraz w orientacji pionowej, pierwotnie mniejszy niż kwadratowe granice, wyświetlany w oryginalnym rozmiarze w ramce, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice: Obraz w orientacji poziomej, pierwotnie większy niż kwadratowe granice, został zmniejszony, aby się w nich zmieścić, przy zachowaniu proporcji. U góry i u dołu widać żółte tło. Obraz źródłowy mniejszy niż granice: Obraz w orientacji poziomej, pierwotnie mniejszy niż kwadratowe granice, wyświetlany w ramce w oryginalnym rozmiarze, z żółtym tłem wokół niego.
ContentScale.None: nie stosuj skalowania do źródła. Jeśli treść jest mniejsza niż granice miejsca docelowego, nie zostanie powiększona, aby dopasować się do obszaru. Obraz źródłowy większy niż granice: Obraz w formacie pionowym, pierwotnie większy niż kwadratowe granice, wyświetlany w oryginalnym rozmiarze, z częściami wystającymi poza górną i dolną krawędź ramki. Obraz źródłowy mniejszy niż granice: Obraz w orientacji pionowej, pierwotnie mniejszy niż kwadratowe granice, wyświetlany w oryginalnym rozmiarze w ramce, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice:Obraz poziomy, pierwotnie większy niż kwadratowe granice, wyświetlany w oryginalnym rozmiarze, z częściami wystającymi poza lewą i prawą stronę ramki.Obraz źródłowy mniejszy niż granice:Obraz w orientacji poziomej, pierwotnie mniejszy niż kwadratowe granice, wyświetlany w ramce w oryginalnym rozmiarze, z żółtym tłem wokół niego.

Przycinanie elementu kompozycyjnego Image do kształtu

Aby dopasować obraz do kształtu, użyj wbudowanego modyfikatora clip. Aby przyciąć obraz do kształtu koła, użyj tego polecenia: 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)
)

Zdjęcie psa wycięte w idealne koło.
Rysunek 1. przycinanie obrazu za pomocą CircleShape,

W przypadku kształtu z zaokrąglonymi rogami użyj Modifier.clip(RoundedCornerShape(16.dp)), podając rozmiar rogów, które mają być zaokrąglone:

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

Kwadratowy obraz psa z zaokrąglonymi rogami.
Rysunek 2. przycinanie obrazu za pomocą RoundedCornerShape,

Możesz też utworzyć własny kształt przycinania, rozszerzając Shape i podając Path, wokół którego ma być przycinany kształt:

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

Kwadratowe zdjęcie psa przycięte do niestandardowego, owalnego kształtu.
Rysunek 3 Przycinanie obrazu za pomocą niestandardowego kształtu ścieżki.

Dodawanie obramowania do komponentu Image

Częstą operacją jest połączenie Modifier.border()Modifier.clip(), aby utworzyć ramkę wokół obrazu:

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

Kwadratowe zdjęcie psa przycięte do kształtu koła z żółtą obwódką.
Rysunek 4. przycięty obraz z obramowaniem;

Aby utworzyć obramowanie z gradientem, możesz użyć interfejsu Brush API do narysowania obramowania z gradientem w kolorach tęczy wokół obrazu:

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

Okrągły obraz przedstawiający psa z tęczowym obramowaniem wokół okrągłego kształtu.
Rysunek 5. Obramowanie koła z gradientem w kolorach tęczy.

Ustawianie niestandardowych proporcji

Aby przekształcić obraz w niestandardowy format obrazu, użyj parametru Modifier.aspectRatio(16f/9f), aby podać niestandardowy format obrazu (lub dowolnego komponentu).

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

Kwadratowy obraz psa przekształcony do formatu 16:9, dzięki czemu jest szerszy i krótszy.
Rysunek 6. Używanie aplikacji Modifier.aspectRatio(16f/9f) na urządzeniu Image.

Filtr kolorów: przekształcanie kolorów pikseli obrazu

Funkcja kompozycyjna Image ma parametr colorFilter, który może zmieniać dane wyjściowe poszczególnych pikseli obrazu.

Zabarwianie obrazów

Użycie ColorFilter.tint(color, blendMode) powoduje zastosowanie trybu mieszania z podanym kolorem do komponentu Image. ColorFilter.tint(color, blendMode) używa BlendMode.SrcIn do zabarwienia treści, co oznacza, że podany kolor jest wyświetlany w miejscu, w którym obraz jest wyświetlany na ekranie. Jest to przydatne w przypadku ikon i wektorów, które muszą mieć inny motyw.

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

Obraz przedstawiający autobus z nałożonym żółtym odcieniem.
Rysunek 7. ColorFilter.tint zastosowano w przypadku BlendMode.SrcIn.

Inne BlendMode wywołują różne efekty. Na przykład ustawienie BlendMode.Darken z symbolem Color.Green na obrazie daje ten wynik:

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

Pies z zieloną poświatą uzyskaną za pomocą BlendMode.Darken, co spowodowało przyciemnienie odcieni zieleni.
Rysunek 8. Color.Green tintBlendMode.Darken.

Więcej informacji o różnych dostępnych trybach mieszania znajdziesz w BlendModedokumentacji referencyjnej.

Stosowanie filtra Image z macierzą kolorów

Przekształć obraz za pomocą opcji matrycy kolorów ColorFilter. Na przykład, aby zastosować filtr czarno-biały do zdjęć, możesz użyć ColorMatrix i ustawić nasycenie na 0f.

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

Pies z zastosowanym filtrem czarno-białym, który usuwa całe nasycenie kolorów.
Rysunek 9. Matryca kolorów z nasyceniem 0 (czarno-biały obraz).

Dostosowywanie kontrastu lub jasności Image komponentu

Aby zmienić kontrast i jasność obrazu, możesz użyć ColorMatrix, aby zmienić wartości:

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

Pies o zwiększonej jasności i kontraście, dzięki czemu wygląda bardziej żywo.
Rysunek 10. Dostosowano jasność i kontrast obrazu za pomocą funkcji ColorMatrix.

Odwracanie kolorów komponentu Image

Aby odwrócić kolory obrazu, ustaw opcję ColorMatrix na odwrócenie kolorów:

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

Pies z odwróconymi kolorami, co daje efekt negatywu.
Rysunek 11. Odwrócone kolory na obrazie.

Rozmywanie komponentu Image

Aby rozmyć obraz, użyj Modifier.blur(), podając radiusXradiusY, które określają promień rozmycia w kierunku poziomym i pionowym.

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

Pies z silnym efektem rozmycia, przez co jest niewyraźny i nieostry.
Rysunek 12. BlurEffect zastosowano do obrazu.

Podczas rozmywania elementu Images zalecamy używanie elementu BlurredEdgeTreatment(Shape) zamiast BlurredEdgeTreatment.Unbounded, ponieważ ten drugi służy do rozmywania dowolnych renderowań, które mają być renderowane poza granicami oryginalnych treści. W przypadku obrazów prawdopodobnie nie będą one renderowane poza granicami treści, natomiast rozmycie zaokrąglonego prostokąta może wymagać tego rozróżnienia.

Jeśli na przykład ustawimy wartość BlurredEdgeTreatment na Unbounded na poprzednim obrazie, krawędzie obrazu będą rozmyte zamiast ostre:

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

Rozmyty obraz psa, w którym rozmycie wykracza poza pierwotne granice obrazu, przez co krawędzie są niewyraźne.
Rysunek 13 BlurEdgeTreatment.Unbounded.