Dostosowywanie obrazu

Obrazy możesz dostosowywać za pomocą właściwości elementu kompozycyjnego Image (contentScale, colorFilter). Możesz też stosować istniejące modyfikatory, aby dodawać różne efekty do elementu Image. Modyfikatorów można używać w dowolnej funkcji kompozycyjnej, nie tylko w funkcji kompozycyjnej Image, podczas gdy contentScale i colorFilter są jawnymi parametrami funkcji kompozycyjnej Image.

Skala treści

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

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

Obraz źródłowy Obraz źródłowy w orientacji pionowej, który przedstawia psa. Źródło w orientacji poziomej, które przedstawia 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 powiększany, aby pasował do granic. Portret psa przeskalowany równomiernie. Pies w orientacji poziomej przeskalowany jednolicie.
ContentScale.Crop: przytnij obraz do środka w dostępnym miejscu. Obraz pionowy przycięty do kwadratu, pokazujący tylko środkową część obrazu. Obraz poziomy przycięty do kwadratowej ramki, pokazujący tylko środkową część obrazu.
ContentScale.FillHeight: skaluje źródło z zachowaniem formatu obrazu, tak aby granice odpowiadały wysokości docelowej. Obraz w orientacji pionowej przeskalowany tak, aby wypełniał wysokość kwadratowej ramki. 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 z zachowaniem formatu obrazu, tak aby granice odpowiadały szerokości docelowej. Obraz pionowy 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, pokazujący pełny 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 docelowe. (Uwaga: powoduje to zniekształcenie obrazów, jeśli umieścisz je w kontenerach, które nie odpowiadają dokładnie współczynnikowi proporcji obrazu). Obraz w orientacji pionowej zniekształcony tak, aby całkowicie wypełniał kwadratową ramkę, co powoduje jego rozciągnięcie. Obraz poziomy zniekształcony tak, aby całkowicie wypełniał kwadratową ramkę, co powoduje jego rozciągnięcie.
ContentScale.Inside: skaluje źródło, aby zachować format obrazu w granicach docelowych. Jeśli źródło jest mniejsze od miejsca docelowego lub równe mu 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 zastosowane skalowanie. Obraz źródłowy większy niż granice: Obraz w orientacji pionowej, który pierwotnie był większy niż kwadratowe obramowanie, został przeskalowany w dół, aby zmieścił się w obramowaniu, z zachowaniem formatu obrazu. Po bokach widać żółte tło. Obraz źródłowy mniejszy niż granice: Obraz pionowy, który pierwotnie był mniejszy niż jego kwadratowe obramowanie, wyświetlany w oryginalnym rozmiarze w ramce, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice: Obraz poziomy, który pierwotnie był większy niż jego kwadratowe obramowanie, został przeskalowany w dół, aby się w nim zmieścił, z zachowaniem współczynnika proporcji. Na górze i na dole widać żółte tło. Obraz źródłowy mniejszy niż granice: Obraz poziomy, który pierwotnie był mniejszy niż jego kwadratowe obramowanie, wyświetlany w oryginalnym rozmiarze w ramce, 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ć ją do obszaru. Obraz źródłowy większy niż granice: Obraz pionowy, który pierwotnie był większy niż jego kwadratowe obramowanie, 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 pionowy, który pierwotnie był mniejszy niż jego kwadratowe obramowanie, wyświetlany w oryginalnym rozmiarze w ramce, z żółtym tłem wokół niego. Obraz źródłowy większy niż granice: Obraz poziomy, który pierwotnie był większy niż jego kwadratowe obramowanie, wyświetlany w oryginalnym rozmiarze, z częściami wystającymi poza lewą i prawą stronę ramki. Obraz źródłowy mniejszy niż granice: Obraz poziomy, który pierwotnie był mniejszy niż jego kwadratowe obramowanie, wyświetlany w oryginalnym rozmiarze w ramce, 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 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 przedstawiający psa przycięty do idealnego okręgu.
Rysunek 1. Wycinanie obrazu za pomocą CircleShape.

Aby uzyskać zaokrąglone rogi, użyj Modifier.clip(RoundedCornerShape(16.dp)), podając rozmiar rogów, które chcesz zaokrąglić:

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

Obraz kwadratowy przedstawiający psa z zaokrąglonymi rogami.
Rysunek 2. Wycinanie obrazu za pomocą RoundedCornerShape.

Możesz też utworzyć własny kształt przycinania, rozszerzając klasę Shape i podając Path dla kształtu, wokół którego ma nastąpić przycięcie:

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

Obraz kwadratowy psa przycięty do niestandardowego, owalnego kształtu.
Rysunek 3. Przycinanie obrazu za pomocą niestandardowego kształtu ścieżki.

Dodawanie obramowania do funkcji kompozycyjnej Image

Często wykonuje się operację polegającą na połączeniu 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)
)

Obraz kwadratowy przedstawiający psa, przycięty do kształtu koła, z żółtą obwódką wokół okrągłego kształtu.
Rysunek 4. Przycięty obraz z obramowaniem.

Aby utworzyć obramowanie gradientowe, możesz użyć interfejsu API Brush i narysować wokół obrazu tęczowe obramowanie gradientowe:

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ęczową ramką wokół okręgu.
Rysunek 5. Tęczowe koło z gradientem.

Ustawianie niestandardowego formatu obrazu

Aby przekształcić obraz do niestandardowego formatu, użyj 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)
)

Obraz kwadratowy psa przekształcony do formatu obrazu 16:9, dzięki czemu jest szerszy i krótszy.
Rysunek 6. Używasz 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.

Obrazy z odcieniami

Użycie ColorFilter.tint(color, blendMode) powoduje zastosowanie trybu mieszania z danym kolorem do komponentu Image. ColorFilter.tint(color, blendMode) używa BlendMode.SrcIn do barwienia treści, co oznacza, że podany kolor jest wyświetlany tam, gdzie obraz jest wyświetlany na ekranie. Jest to przydatne w przypadku ikon i grafiki wektorowej, 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 żółtym odcieniem.
Rysunek 7. ColorFilter.tint zastosowano w przypadku BlendMode.SrcIn.

Inne BlendMode dają różne efekty. Na przykład ustawienie BlendMode.Darken z Color.Green na obrazie daje taki 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 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.

Zastosuj filtr Image z macierzą kolorów

Przekształć obraz za pomocą opcji macierzy kolorów ColorFilter. Na przykład aby 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 elementu kompozycyjnego Image

Aby zmienić kontrast i jasność obrazu, możesz użyć ColorMatrix i 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 ze zwiększoną jasnością i kontrastem, dzięki czemu wygląda bardziej wyraziście.
Rysunek 10. Dostosowano jasność i kontrast obrazu za pomocą narzędzia ColorMatrix.

Odwracanie kolorów elementu kompozycyjnego Image

Aby odwrócić kolory obrazu, ustaw ColorMatrix na odwracanie 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 funkcji kompozycyjnej Image

Aby rozmyć obraz, użyj Modifier.blur(), podając radiusX i radiusY, które określają promień rozmycia odpowiednio 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, który sprawia, że jest niewyraźny i nieostry.
Rysunek 12. BlurEffect zastosowano do obrazu.

Do rozmywania elementu Images zalecamy używanie BlurredEdgeTreatment(Shape) zamiast BlurredEdgeTreatment.Unbounded, ponieważ ten drugi jest używany 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, podczas gdy rozmycie zaokrąglonego prostokąta może wymagać takiego rozróżnienia.

Jeśli na przykład na poprzednim obrazie ustawimy właściwość BlurredEdgeTreatment na Unbounded, krawędzie obrazu będą rozmyte, a nie 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ą niewyraźne.
Rysunek 13. BlurEdgeTreatment.Unbounded.