Rozmycie w Compose

Efekty rozmycia zmiękczają szczegóły wizualne, tworzą fotograficzną głębię ostrości i przyciągają uwagę do elementów interfejsu na pierwszym planie. W Jetpack Compose użyj Modifier.blur, aby rozmyć zawartość narysowaną w funkcji kompozycyjnej, w tym obrazy, kształty, tekst i kontenery układu. Zastosowanie Modifier.blur powoduje renderowanie elementu kompozycyjnego w osobnej warstwie graficznej.

Po lewej: oryginalny obraz. Środek: obraz z jednolitym rozmyciem zastosowanym na całej powierzchni. Po prawej: obraz z progresywnym rozmyciem, który jest ostry u góry i coraz bardziej rozmyty u dołu.
Rysunek 1. Po lewej: oryginalny obraz. Środek: obraz z jednolitym rozmyciem zastosowanym na całej powierzchni. Po prawej: obraz z progresywnym rozmyciem, które jest ostre u góry i zwiększa się ku dołowi.

W zależności od celów projektowych możesz zmieniać rozmycie na 2 sposoby:

  • Jednolite rozmycie: stosuje stały promień rozmycia w całym elemencie kompozycyjnym, równomiernie na obu osiach lub z niezależnymi promieniami poziomymi i pionowymi (radiusX, radiusY).
  • Rozmycie progresywne: zmienia promień rozmycia w przestrzeni w funkcji kompozycyjnej za pomocą gradientów BlurRadiusSpec lub niestandardowego Shader.

Zastosuj jednolite rozmycie

Aby zastosować stałe rozmycie w całym elemencie kompozycyjnym, przekaż promień Dp do Modifier.blur. Przekaż pojedynczą wartość radius, aby rozmyć zawartość w równym stopniu wzdłuż osi poziomej (X) i pionowej (Y):

@Composable
fun UniformBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                radius = 8.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Pies równomiernie rozmyty w osiach poziomej i pionowej.
Rysunek 2. Pies rozmyty równomiernie w osiach poziomej i pionowej.

Aby utworzyć efekt kierunkowego rozmycia, przekaż do Modifier.blur osobne wartości radiusX i radiusY. Aby efekt rozmycia został zastosowany, zarówno radiusX, jak i radiusY muszą być większe niż 0.dp, jak w tym przykładzie:

@Composable
fun DirectionalBlurExample() {
    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 = 2.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Pies z silnym efektem rozmycia ruchu w poziomie.
Rysunek 3. Obraz kwadratowy przedstawiający psa z silnym efektem rozmycia ruchu w poziomie.

Zastosuj rozmycie progresywne

Progresywne rozmycie zmienia promień rozmycia w funkcji kompozycyjnej, tworząc płynne przejście między ostrymi i rozmytymi obszarami.

Przekaż BlurRadiusSpec do Modifier.blur. Możesz na przykład użyć właściwości BlurRadiusSpec.verticalGradient z wartościami startRadius = 0.dp i endRadius = 6.dp, aby zachować ostrość górnej części obrazu i stopniowo rozmywać go w kierunku dołu, jak w tym przykładzie:

@Composable
fun ProgressiveBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Sharp at the top (0.dp), progressively blurred toward the bottom (6.dp)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    startRadius = 0.dp,
                    endRadius = 6.dp,
                ),
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Pies, który jest ostry u góry i stopniowo staje się rozmyty u dołu.
Rysunek 4. Obraz przedstawiający psa, który jest ostry u góry i stopniowo staje się rozmyty u dołu.

Określanie gradientów rozmycia za pomocą BlurRadiusSpec

W aplikacji BlurRadiusSpec wymiary są ustawiane w Dp i automatycznie dostosowywane do rozmiaru warstwy i gęstości wyświetlania podczas rysowania. Rozmycia zmienne przestrzennie są ograniczone do 150 pikseli po konwersji, podczas gdy BlurRadiusSpec.uniform nie ma ograniczeń.

W tabeli poniżej znajdziesz funkcje fabryczne dostępne w BlurRadiusSpec:

Fabryka: BlurRadiusSpec Opis
BlurRadiusSpec.verticalGradient Płynnie zmienia promień rozmycia w pionie od góry (0f) do dołu (1f) warstwy.
BlurRadiusSpec.horizontalGradient Płynnie zmienia promień rozmycia w poziomie od lewej krawędzi (0f) do prawej (1f).
BlurRadiusSpec.linearGradient Stosuje przejście z rozmyciem kierunkowym wzdłuż linii prostej łączącej określone współrzędne DpOffset.
BlurRadiusSpec.radialGradient Rozprowadza rozmycie na zewnątrz od punktu centralnego w kierunku granicy fallOffRadius.
BlurRadiusSpec.uniform Stosuje równomierny promień rozmycia na całej warstwie.
BlurRadiusSpec.shader Używa kanału alfa niestandardowego elementu Shader do kontrolowania i skalowania elementu maxRadius na każdym pikselu.

Dostosuj rozkład rozmycia za pomocą BlurStop

Standardowe rozmycia gradientowe są interpolowane liniowo między 0f a 1f. Aby dostosować rozkład rozmycia na powierzchni, np. rozmyć kilka krawędzi lub zachować całkowitą ostrość środkowej sekcji, przekaż List<BlurStop> zawierający od 2 do 16 wpisów BlurStop do verticalGradient, horizontalGradient, linearGradient lub radialGradient. Dla każdego wpisu BlurStop określ te parametry:

  • fraction: względna pozycja wzdłuż gradientu od 0.0f do 1.0f. Przystanki są automatycznie sortowane według ułamka.
  • radius: promień rozmycia w Dp zastosowany w tej pozycji ułamkowej.

Na przykład 4 punkty rozmywają górną i dolną krawędź obrazu, zachowując całkowitą ostrość środka, jak w tym przykładzie:

@Composable
fun MultiStopBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Blurred at the top and bottom edges, sharp in the middle (0.3f..0.7f)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    stops = listOf(
                        BlurStop(fraction = 0.0f, radius = 20.dp),
                        BlurStop(fraction = 0.3f, radius = 0.dp),
                        BlurStop(fraction = 0.7f, radius = 0.dp),
                        BlurStop(fraction = 1.0f, radius = 20.dp),
                    ),
                ),
                edgeTreatment = BlurredEdgeTreatment.Unbounded,
            ),
    )
}

Pies z rozmytymi górnymi i dolnymi krawędziami oraz ostrym środkowym poziomym pasem.
Rysunek 5. Obraz przedstawiający psa z rozmytymi górnymi i dolnymi krawędziami oraz ostrym środkowym pasem poziomym.

Konfigurowanie właściwości warstwy za pomocą BlurScope

Zamiast przekazywać bezpośrednio blurRadiusSpec, możesz przekazać blok konfiguracji do Modifier.blur { ... }. Ten blok działa wewnątrz BlurScope, co daje bezpośredni dostęp do gęstości układu i tych właściwości:

  • size: DpSize: zmierzona szerokość i wysokość rozmytej warstwy w Dp, która definiuje przestrzeń współrzędnych dla geometrii gradientu.
  • blurRadiusSpec: BlurRadiusSpec: konfiguracja promienia rozmycia na powierzchni. Domyślna wartość to BlurRadiusSpec.uniform(0.dp) (brak rozmycia).
  • edgeTreatment: BlurredEdgeTreatment: strategia używana do próbkowania i przycinania pikseli poza granicami treści. Domyślna wartość to BlurredEdgeTreatment.Rectangle.
  • alpha: Float: nieprzezroczystość rozmytej warstwy w zakresie 0f..1f. Domyślna wartość to 1f.

Blok BlurScope działa w fazie warstwy graficznej, po pomiarze i układzie, więc możesz obliczyć geometrię gradientu z size bez wywoływania rekompozycji.

Kontrolowanie przycinania krawędzi za pomocą BlurredEdgeTreatment

Ponieważ rozmycie próbkuje sąsiednie piksele w promieniu rozmycia, rozmyte dane wyjściowe wykraczają poza granice oryginalnej treści o promień rozmycia. BlurredEdgeTreatment określa, jak próbkowane są piksele poza oryginalnymi granicami i czy wynik jest przycinany do kształtu.

BlurredEdgeTreatment działa zarówno z rozmyciem jednolitym, jak i progresywnym:

BlurredEdgeTreatment Zachowanie Wyniki
BlurredEdgeTreatment.Rectangle (domyślnie) Przycina wynik rozmycia do prostokątnych granic oryginalnej treści i pobiera próbki najbliższych pikseli krawędzi (TileMode.Clamp). Rozmyty obraz psa przycięty do ostrej prostokątnej granicy.
BlurredEdgeTreatment(shape) Przycina wynik rozmycia do określonego kształtu Shape (np. RoundedCornerShape(8.dp)) i pobiera próbki najbliższych pikseli krawędzi (TileMode.Clamp). Zachowuje ostrość wyniku rozmycia na granicy kształtu bez wychodzenia poza pierwotne granice. Rozmyty obraz psa przycięty do kształtu z zaokrąglonymi rogami i ostrymi krawędziami.
BlurredEdgeTreatment.Unbounded Nie przycina wyniku rozmycia (TileMode.Decal). Piksele poza granicami treści są próbkowane jako przezroczysta czerń, co sprawia, że zewnętrzne krawędzie obrazu wydają się rozmyte i rozmazane poza oryginalnymi granicami. Rozmyty obraz psa, którego krawędzie łagodnie zanikają poza pierwotnymi granicami.

Aby zobaczyć, jak te interfejsy API łączą się w pełne wzorce interfejsu, takie jak zanikanie krawędzi przewijanych treści, wyróżnianie punktu centralnego lub maskowanie rozmycia za pomocą niestandardowego shadera, zapoznaj się z artykułem Typowe przypadki użycia rozmycia.