Dostosowywanie obrazu

Obrazy możesz dostosowywać za pomocą właściwości komponentu Image (contentScale, colorFilter). Możesz też stosować istniejące modyfikatory aby dodawać do komponentu Image różne efekty. Modyfikatory można stosować do dowolnego komponentu, nie tylko do komponentu Image, natomiast contentScale i colorFilter to jawne parametry komponentu Image.

Skala treści

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

W tym przykładzie komponent Image jest ograniczony do rozmiaru 150 dp z obramowaniem, a tło jest ustawione na żółte w komponencie 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 różne wyniki. Tabela poniżej pomoże Ci wybrać odpowiedni tryb ContentScale:

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 w orientacji poziomej:
ContentScale.Fit: skaluje obraz równomiernie, zachowując współczynnik proporcji (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: przycina obraz do środka 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ę, pokazujący tylko środkową część obrazu.
ContentScale.FillHeight: skaluje źródło, zachowując współczynnik proporcji, tak aby granice pasowały do wysokości docelowej. Obraz w formacie pionowym, przeskalowany tak, aby wypełniał wysokość kwadratowej ramki. Cały obraz jest widoczny, a po lewej i prawej stronie widać żółte tło. Obraz poziomy przeskalowany tak, aby wypełniał wysokość kwadratowej ramki, z przyciętymi bokami.
ContentScale.FillWidth: skaluje źródło, zachowując współczynnik proporcji, tak aby granice pasowały do szerokości docelowej. Obraz w formacie pionowym 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 docelowe. (Uwaga: powoduje to zniekształcenie obrazów, jeśli umieścisz je w kontenerach, które nie pasują do dokładnego współczynnika proporcji 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łnić kwadratową ramkę, co powoduje rozciągnięcie obrazu.
ContentScale.Inside: skaluje źródło, aby zachować współczynnik proporcji w obrębie granic docelowych. Jeśli źródło jest mniejsze lub równe miejscu docelowemu w obu wymiarach, zachowuje się podobnie jak None. Treść będzie zawsze 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. 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 stosuje żadnego skalowania do źródła. Jeśli treść jest mniejsza niż granice docelowe, nie zostanie przeskalowana, 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 komponentu 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 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)
)

Obraz psa wycięty w idealne koło.
Rysunek 1. Przycinanie obrazu za pomocą CircleShape.

Aby uzyskać kształt 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 dla kształtu, wokół którego ma być przycinany obraz:

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 łączenie Modifier.border() z Modifier.clip(), aby utworzyć obramowanie 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. Obraz z obramowaniem.

Aby utworzyć obramowanie gradientowe, możesz użyć interfejsu API Brush, aby narysować obramowanie gradientowe 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 niestandardowego współczynnika proporcji

Aby przekształcić obraz w niestandardowy współczynnik proporcji, użyj Modifier.aspectRatio(16f/9f), aby podać niestandardowy współczynnik proporcji 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 w format obrazu 16:9, dzięki czemu jest szerszy i krótszy.
Rysunek 6. Używanie Modifier.aspectRatio(16f/9f) w komponencie Image.

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

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

Barwienie 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 wymagają innego motywu.

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 zastosowany z BlendMode.SrcIn.

Inne BlendMode powodują różne efekty. Na przykład ustawienie BlendMode.Darken z Color.Green na obrazie daje taki efekt:

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 zielonym odcieniem zastosowanym za pomocą BlendMode.Darken, co daje ciemniejsze odcienie zieleni.
Rysunek 8. Color.Green tint z BlendMode.Darken.

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

Stosowanie filtra Image za pomocą matrycy kolorów

Przekształć obraz za pomocą opcji matrycy kolorów ColorFilter. Aby na przykład, zastosować filtr czarno-biały do obrazów, 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 (obraz czarno-biały).

Dostosowywanie kontrastu lub jasności komponentu Image

Aby zmienić kontrast i jasność obrazu, możesz użyć the ColorMatrix do zmiany 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. Dostosowana jasność i kontrast obrazu za pomocą ColorMatrix.

Odwracanie kolorów komponentu Image

Aby odwrócić kolory obrazu, ustaw ColorMatrix tak, aby odwracała kolory:

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 radiusX i radiusY, które określają odpowiednio 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 zastosowany do obrazu.

Podczas rozmywania Images zalecamy używanie BlurredEdgeTreatment(Shape) zamiast BlurredEdgeTreatment.Unbounded, ponieważ ta druga opcja służy do rozmywania dowolnych renderowań, które mają być renderowane poza granicami oryginalnej 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 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, na którym rozmycie wykracza poza pierwotne granice obrazu, przez co krawędzie są rozmyte.
Rysunek 13. BlurEdgeTreatment.Unbounded.