Dostosowywanie obrazu

Obrazy możesz dostosowywać za pomocą właściwości w Image komponowalnym (contentScale, 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 są jawnymi parametrami 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. Obraz w formacie pionowym przeskalowany tak, aby wypełniał 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 formacie pionowym przeskalowany tak, aby wypełniał szerokość kwadratowej ramki, z przyciętą górą i dołem. Obraz poziomy przeskalowany tak, aby wypełniał szerokość kwadratowej ramki. Cały obraz z żółtym tłem widocznym u góry i u dołu.
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 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: Skaluj ź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 ramce w oryginalnym rozmiarze, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice:Obraz panoramiczny, pierwotnie większy niż jego kwadratowe granice, został zmniejszony, aby się w nich zmieścić, przy zachowaniu współczynnika proporcji. Na górze i na dole 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 wypełnić obszar. 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 ramce w oryginalnym rozmiarze, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice: Obraz w orientacji poziomej, 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))
)

Kwadratowe zdjęcie 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ętym obrazem z ramką,

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 psa z tęczowym gradientem wokół okręgu.
Rysunek 5. Obramowanie koła z gradientem w kolorach tęczy.

Ustawianie niestandardowych proporcji

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

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 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 barwienia 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. Zastosowano ustawienie ColorFilter.tint z wartością 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 powoduje ciemniejsze odcienie zieleni.
Rysunek 8. Color.Green tintBlendMode.Darken.

Więcej informacji o dostępnych trybach mieszania znajdziesz w BlendModedokumentacji referencyjnej.

Stosowanie filtra Image z macierzą kolorów

Przekształć obraz za pomocą opcji ColorFiltermatryca kolorówColorFilter. 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 elementu Image

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 z większą jasnością i kontrastem, 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 ostatni 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.