Modificadores de Compose

Los modificadores te permiten decorar o aumentar un elemento componible. Por ejemplo, puedes hacer todo esto:

  • Cambiar el tamaño, el diseño, el comportamiento y el aspecto del elemento componible
  • Agregar información (p. ej., etiquetas de accesibilidad)
  • Procesar entradas del usuario
  • Agregar interacciones de nivel superior, (p. ej., hacer que un elemento sea apto para hacer clic, desplazable, arrastrable o ampliable)

Los modificadores son objetos estándar de Kotlin. Para crear uno, llama a una de las funciones de clase Modifier.

import androidx.compose.ui.Modifier

@Composable
private fun Greeting(name: String) {
  Column(modifier = Modifier.padding(24.dp)) {
    Text(text = "Hello,")
    Text(text = name)
  }
}

Dos líneas de texto sobre un fondo de color con padding alrededor del texto

Puedes encadenar estas funciones para crear una composición:

@Composable
private fun Greeting(name: String) {
  Column(modifier = Modifier
    .padding(24.dp)
    .fillMaxWidth()
  ) {
    Text(text = "Hello,")
    Text(text = name)
  }
}

El fondo de color detrás del texto ahora extiende todo el ancho del dispositivo.

En el código anterior, observa distintas funciones de modificadores que se usan juntas.

  • padding coloca espacio alrededor de un elemento.
  • fillMaxWidth hace que el elemento componible ocupe el ancho máximo que le otorga su elemento superior.

La práctica recomendada es que todos los elementos componibles acepten un parámetro modifier y pasen ese modificador al primer elemento secundario que emita la IU. Si lo haces, tu código será más reutilizable y su comportamiento será más intuitivo y predecible. Para obtener más información, consulta los lineamientos de la API de Compose Cómo aceptar y respetar elementos de un parámetro modificador.

El orden de los modificadores es importante

El orden de las funciones de los modificadores es importante. Como cada función realiza cambios en el Modifier que muestra la función anterior, la secuencia afecta al resultado final. Veamos un ejemplo:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

Toda el área, incluso el padding alrededor de los bordes, responde a los clics

En el código anterior, se puede hacer clic en toda el área, incluso en el padding que la rodea, porque se aplicó el modificador padding después del modificador clickable. Si se invierte el orden de los modificadores, el espacio que agrega padding no reacciona a la entrada del usuario:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .padding(padding)
            .clickable(onClick = onClick)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

El padding alrededor del borde del diseño ya no responde a los clics

Modificadores integrados

Jetpack Compose proporciona una lista de modificadores integrados para ayudarte a decorar o aumentar un elemento componible. A continuación, se muestran algunos modificadores comunes que usarás para ajustar tus diseños.

Padding y tamaño

De forma predeterminada, los diseños proporcionados en Compose unen sus objetos secundarios. Sin embargo, puedes establecer un tamaño con el modificador size:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(/*...*/)
        Column { /*...*/ }
    }
}

Ten en cuenta que el tamaño especificado podría no respetarse si no cumple con las restricciones provenientes del elemento superior del diseño. Si necesitas que el tamaño del elemento componible se corrija independientemente de las restricciones entrantes, usa el modificador requiredSize:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.requiredSize(150.dp)
        )
        Column { /*...*/ }
    }
}

La imagen secundaria es más grande que las restricciones que provienen de su elemento superior

En este ejemplo, incluso con el height superior establecido en 100.dp, la altura de la Image será 150.dp, ya que el modificador requiredSize tiene prioridad.

Si quieres que un diseño secundario rellene todo el alto disponible que permite el elemento superior, agrega el modificador fillMaxHeight (Compose también proporciona fillMaxSize y fillMaxWidth):

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.fillMaxHeight()
        )
        Column { /*...*/ }
    }
}

La altura de la imagen es tan grande como la del elemento superior

Para agregar padding a un elemento, establece un modificador padding.

Si deseas agregar padding sobre un modelo de referencia de texto para alcanzar una distancia específica desde la parte superior del diseño al modelo de referencia, usa el modificador paddingFromBaseline:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(
                text = artist.name,
                modifier = Modifier.paddingFromBaseline(top = 50.dp)
            )
            Text(artist.lastSeenOnline)
        }
    }
}

Texto con padding encima

Desplazamiento

Para posicionar un diseño relacionado con su posición original, agrega el modificador offset y configura el desplazamiento en los ejes y y x. Las compensaciones pueden ser positivas y no positivas. La diferencia entre padding y offset es que agregar un offset a un elemento componible no cambia sus mediciones:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(artist.name)
            Text(
                text = artist.lastSeenOnline,
                modifier = Modifier.offset(x = 4.dp)
            )
        }
    }
}

El texto se movió al lado derecho del contenedor superior

El modificador offset se aplica horizontalmente según la dirección del diseño. En un contexto de izquierda a derecha, un offset positivo cambia el elemento hacia la derecha, mientras que en un contexto de derecha a izquierda, desplaza el elemento hacia la izquierda. Si necesitas establecer un desplazamiento sin considerar la dirección del diseño, consulta el modificador absoluteOffset, en el que un valor de desplazamiento positivo siempre cambia el elemento hacia la derecha.

Seguridad de tipo en Compose

En Compose, existen modificadores que solo funcionan cuando se aplican a elementos secundarios de determinados elementos que admiten composición. Por ejemplo, si deseas que un elemento secundario sea tan grande como el elemento Box superior sin afectar el tamaño de Box, usa el modificador matchParentSize.

Compose aplica de manera forzosa esta seguridad de tipo mediante alcances personalizados. Por ejemplo, matchParentSize solo está disponible en BoxScope. Por lo tanto, solo se puede usar cuando se usa el elemento secundario dentro de un Box.

Los modificadores con alcance notifican al elemento superior sobre cierta información del elemento secundario que el superior debe conocer. Por lo general, también se los conoce como modificadores de datos del elemento superior. Sus aspectos internos difieren de los modificadores de uso general, pero, desde una perspectiva de uso, estas diferencias no resultan importantes.

matchParentSize en el cuadro

Como se mencionó con anterioridad, si deseas que un diseño secundario tenga el mismo tamaño que un elemento Box superior sin afectar el tamaño del Box, usa el modificador matchParentSize.

Ten en cuenta que matchParentSize solo está disponible dentro de un alcance de Box, lo que significa que solo se aplica a campos secundarios directos de elementos componibles Box.

En el siguiente ejemplo, el Spacer secundario toma su tamaño desde el elemento Box superior, que, a su vez, toma su tamaño del elemento secundario más grande, ArtistCard en este caso.

@Composable
fun MatchParentSizeComposable() {
    Box {
        Spacer(Modifier.matchParentSize().background(Color.LightGray))
        ArtistCard()
    }
}

Fondo gris que rellena su contenedor

Si se usara fillMaxSize en lugar de matchParentSize, Spacer tomaría todo el espacio disponible para el elemento superior, lo que podría hacer que este se expanda y rellene todo el espacio disponible.

Fondo gris que ocupa toda la pantalla

weight en Row y Column

Como viste en la sección anterior Padding y tamaño, el tamaño de un objeto componible se define de forma predeterminada según el contenido al que está unido. Puedes configurar el tamaño de un elemento componible para que sea flexible dentro de su elemento superior usando el modificador weight que solo está disponible en RowScope y ColumnScope.

Tomemos un objeto Row que contiene dos elementos componibles Box. El primer cuadro recibe el doble de weight del segundo, por lo que recibe el doble del ancho. Dado que Row tiene 210.dp de ancho, el primer elemento Box tendrá 140.dp de ancho, y el segundo, 70.dp:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            /*...*/
            modifier = Modifier.weight(2f)
        )
        Column(
            modifier = Modifier.weight(1f)
        ) {
            /*...*/
        }
    }
}

El ancho de la imagen es el doble del ancho del texto

Más información

Proporcionamos una lista completa de modificadores, con sus parámetros y alcances.