Cómo desenfocar en Compose

Los efectos de desenfoque suavizan los detalles visuales, crean una profundidad de campo fotográfica y atraen la atención hacia los elementos de la IU en primer plano. En Jetpack Compose, usa Modifier.blur para desenfocar el contenido dibujado dentro de un elemento componible, incluidas las imágenes, las formas, el texto y los contenedores de diseño. Aplicar Modifier.blur renderiza el elemento componible en una capa de gráficos independiente.

Izquierda: la imagen original. Centro: La imagen con un desenfoque uniforme aplicado en toda la superficie. Derecha: la imagen con un desenfoque progresivo que es nítido en la parte superior y aumenta hacia la parte inferior.
Figura 1: Izquierda: la imagen original. Centro: la imagen con un desenfoque uniforme aplicado en toda la superficie. A la derecha, la imagen con un desenfoque progresivo que es nítido en la parte superior y aumenta hacia la parte inferior.

Según tus objetivos de diseño, puedes variar el desenfoque de dos maneras:

  • Desenfoque uniforme: Aplica un radio de desenfoque constante en todo el elemento componible, ya sea de forma equitativa en ambos ejes o con radios horizontales y verticales independientes (radiusX, radiusY).
  • Desenfoque progresivo: Varía el radio de desenfoque de forma espacial en el elemento componible con gradientes BlurRadiusSpec o un Shader personalizado.

Cómo aplicar un desenfoque uniforme

Para aplicar un desenfoque constante en todo un elemento componible, pasa un radio Dp a Modifier.blur. Pasa un solo valor radius para desenfocar el contenido de manera uniforme en los ejes horizontal (X) y vertical (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)),
            ),
    )
}

Un perro desenfocado de manera uniforme en los ejes horizontal y vertical.
Figura 2: Un perro desenfocado de manera uniforme en los ejes horizontal y vertical.

Para crear un efecto de desenfoque de movimiento direccional, pasa valores radiusX y radiusY independientes a Modifier.blur. Tanto radiusX como radiusY deben ser mayores que 0.dp para que se aplique el efecto de desenfoque, como se muestra en el siguiente ejemplo:

@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)),
            ),
    )
}

Un perro con un fuerte efecto de desenfoque de movimiento horizontal.
Figura 3: Una imagen cuadrada de un perro con un fuerte efecto de desenfoque de movimiento horizontal.

Aplica un desenfoque progresivo

Un desenfoque progresivo varía el radio de desenfoque en un elemento componible, lo que crea una transición fluida entre las regiones nítidas y desenfocadas.

Pasa un BlurRadiusSpec a Modifier.blur. Por ejemplo, usa BlurRadiusSpec.verticalGradient con startRadius = 0.dp y endRadius = 6.dp para mantener nítida la parte superior de una imagen mientras se desenfoca progresivamente hacia la parte inferior, como se muestra en el siguiente ejemplo:

@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)),
            ),
    )
}

Un perro que se ve nítido en la parte superior y se vuelve borroso gradualmente hacia la parte inferior.
Figura 4: Una imagen de un perro que se ve nítida en la parte superior y se vuelve borrosa gradualmente hacia la parte inferior.

Especifica gradientes de desenfoque con BlurRadiusSpec

En BlurRadiusSpec, las mediciones se establecen en Dp y se ajustan automáticamente al tamaño y la densidad de visualización de la capa cuando se dibujan. Los desenfoques que varían espacialmente se limitan a 150 píxeles una vez convertidos, mientras que BlurRadiusSpec.uniform no tiene límite.

En la siguiente tabla, se enumeran las funciones de fábrica disponibles en BlurRadiusSpec:

Fábrica de BlurRadiusSpec Descripción
BlurRadiusSpec.verticalGradient Cambia de forma fluida el radio de desenfoque verticalmente de arriba (0f) a abajo (1f) en toda la capa.
BlurRadiusSpec.horizontalGradient Cambia suavemente el radio de desenfoque de forma horizontal desde el borde izquierdo (0f) hasta el borde derecho (1f).
BlurRadiusSpec.linearGradient Aplica una transición de desenfoque direccional a lo largo de una línea recta que conecta coordenadas DpOffset específicas.
BlurRadiusSpec.radialGradient Extiende el desenfoque hacia afuera desde un punto focal hacia el límite de fallOffRadius.
BlurRadiusSpec.uniform Aplica un radio de desenfoque uniforme en toda la capa.
BlurRadiusSpec.shader Usa el canal alfa de un Shader personalizado para controlar y escalar el maxRadius en cada píxel.

Personaliza la distribución del desenfoque con BlurStop

Los desenfoques de gradiente estándar se interpolan de forma lineal entre 0f y 1f. Para personalizar la distribución del desenfoque en una superficie, como desenfocar varios bordes o mantener una sección central completamente nítida, pasa un List<BlurStop> que contenga de 2 a 16 entradas BlurStop a verticalGradient, horizontalGradient, linearGradient o radialGradient. Define lo siguiente para cada entrada BlurStop:

  • fraction: Es la posición relativa a lo largo del gradiente de 0.0f a 1.0f. Los puntos de parada se ordenan automáticamente por fracción.
  • radius: Es el radio de desenfoque en Dp que se aplica en esa posición de fracción.

Por ejemplo, cuatro paradas desenfocan los bordes superior e inferior de una imagen, mientras que mantienen el centro completamente nítido, como se muestra en el siguiente ejemplo:

@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,
            ),
    )
}

Un perro con los bordes superior e inferior desenfocados, mientras que la franja horizontal central se mantiene enfocada con nitidez.
Figura 5: Una imagen de un perro con los bordes superior e inferior desenfocados, mientras que la franja horizontal central se mantiene enfocada con nitidez.

Configura las propiedades de la capa con BlurScope

En lugar de pasar blurRadiusSpec directamente, puedes pasar un bloque de configuración a Modifier.blur { ... }. Este bloque se ejecuta dentro de BlurScope, lo que te brinda acceso directo a la densidad del diseño y a las siguientes propiedades:

  • size: DpSize: Es el ancho y la altura medidos de la capa desenfocada en Dp, que define el espacio de coordenadas para la geometría del gradiente.
  • blurRadiusSpec: BlurRadiusSpec: Es la configuración del radio de desenfoque en toda la superficie. La configuración predeterminada es BlurRadiusSpec.uniform(0.dp) (sin desenfoque).
  • edgeTreatment: BlurredEdgeTreatment: Es la estrategia que se usa para muestrear y recortar píxeles fuera de los límites del contenido. La configuración predeterminada es BlurredEdgeTreatment.Rectangle.
  • alpha: Float: Es la opacidad de la capa desenfocada en el rango de 0f..1f. La configuración predeterminada es 1f.

Debido a que el bloque BlurScope se ejecuta durante la fase de la capa de gráficos, después de la medición y el diseño, puedes calcular la geometría del gradiente a partir de size sin activar la recomposición.

Controla el recorte de bordes con BlurredEdgeTreatment

Debido a que el desenfoque toma muestras de los píxeles vecinos dentro del radio de desenfoque, el resultado desenfocado se extiende más allá de los límites del contenido original según el radio de desenfoque. BlurredEdgeTreatment determina cómo se muestrean los píxeles fuera de los límites originales y si el resultado se recorta a una forma.

BlurredEdgeTreatment funciona con desenfoques uniformes y progresivos:

BlurredEdgeTreatment Comportamiento Salida
BlurredEdgeTreatment.Rectangle (predeterminada) Recorta el resultado del desenfoque a los límites rectangulares del contenido original y muestra los píxeles de borde más cercanos (TileMode.Clamp). Una imagen de un perro desenfocada y recortada con un límite rectangular nítido.
BlurredEdgeTreatment(shape) Recorta el resultado del desenfoque según el Shape especificado (como RoundedCornerShape(8.dp)) y toma muestras de los píxeles de borde más cercanos (TileMode.Clamp). Mantiene nítido el resultado del desenfoque en el límite de la forma sin que se extienda fuera de los límites originales. Una imagen de un perro desenfocada y recortada en una forma de esquina redondeada con bordes nítidos.
BlurredEdgeTreatment.Unbounded No recorta el resultado del desenfoque (TileMode.Decal). Los píxeles fuera de los límites del contenido muestran un negro transparente, lo que hace que los bordes exteriores de la imagen se vean borrosos y difuminados más allá de los límites originales. Una imagen de un perro desenfocada cuyos bordes se desvanecen suavemente más allá de los límites originales.

Para ver cómo se combinan estas APIs en patrones de IU completos, como atenuar los bordes del contenido que se desplaza, destacar un punto focal o enmascarar un desenfoque con un sombreador personalizado, consulta Casos de uso comunes de desenfoque.