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
.
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
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) } }
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 } }
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 } }
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 size
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 { /*...*/ } } }
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 { /*...*/ } } }
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) } } }
Desplazamiento
Para posicionar un diseño en relación con su posición original, agrega el modificador offset
y configura el desplazamiento en los ejes x y y.
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 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.
El modificador offset
proporciona dos sobrecargas: offset
, que toma las compensaciones como parámetros, y offset
, que toma en una lambda.
Para obtener información más detallada sobre cuándo usar cada una de ellas y cómo optimizar el rendimiento, lee la sección Rendimiento de Compose: aplazar las lecturas el mayor tiempo posible.
Seguridad del alcance en Compose
En Compose, existen modificadores que solo se pueden usar cuando se aplican a elementos secundarios de determinados elementos componibles. Compose aplica esto mediante alcances personalizados.
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
. matchParentSize
solo está disponible en BoxScope
.
Por lo tanto, solo se puede usar en un elemento secundario dentro de un elemento superior Box
.
La seguridad del alcance te impide agregar modificadores que no funcionarían en otros elementos componibles y permisos, y te ahorra tiempo de prueba y error.
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 Box
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() } }
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.
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) ) { /*...*/ } } }
Extraer y reutilizar modificadores
Se pueden encadenar varios modificadores para decorar o aumentar un elemento componible. Esta cadena se crea a través de la interfaz Modifier
, que representa una lista inmutable y ordenada de una sola Modifier.Elements
.
Cada Modifier.Element
representa un comportamiento individual, como los comportamientos de diseño, dibujo y gráficos, todos los comportamientos de gestos, enfoque y semántica, así como los eventos de entrada de dispositivos. El orden es importante: los elementos modificadores que se agreguen primero se aplicarán primero.
A veces, puede ser beneficioso reutilizar las mismas instancias de cadena de modificadores en varios elementos componibles al extraerlos en variables y elevarlos a alcances más altos. Esto puede mejorar la legibilidad del código o mejorar el rendimiento de tu app por varios motivos:
- La reasignación de los modificadores no se repetirá cuando se produzca la recomposición de elementos componibles que los usan
- Las cadenas modificadoras pueden ser muy largas y complejas, por lo que reutilizar la misma instancia de una cadena puede aliviar la carga de trabajo que necesita el entorno de ejecución de Compose cuando se comparan.
- Esta extracción promueve la limpieza, la coherencia y el mantenimiento del código en su base
Prácticas recomendadas para reutilizar modificadores
Crea tus propias cadenas de Modifier
y extráelas para reutilizarlas en varios componentes componibles. Está bien guardar un modificador, ya que son objetos similares a los datos:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Extraer y reutilizar modificadores cuando se observa un estado que cambia con frecuencia
Cuando se observan estados que cambian con frecuencia dentro de elementos componibles, como estados de animación o scrollState
, puede haber una cantidad significativa de recomposiciones. En este caso, tus modificadores se asignarán en cada recomposición y, posiblemente, en cada fotograma:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
En su lugar, puedes crear, extraer y reutilizar la misma instancia del modificador y pasarla al elemento componible de la siguiente manera:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
Extraer y reutilizar modificadores sin alcance
Los modificadores pueden tener o no alcance a un elemento componible específico. En el caso de los modificadores sin alcance, puedes extraerlos fácilmente fuera de cualquier elemento componible como variables simples:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Esto puede ser especialmente beneficioso cuando se combina con diseños diferidos. En la mayoría de los casos, querrás que todos los elementos potencialmente significativos tengan los mismos modificadores:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
Extraer y reutilizar modificadores con alcance
Cuando se trata de modificadores con alcance a ciertos elementos componibles, puedes extraerlos al nivel más alto posible y volver a usarlos cuando corresponda:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
Solo debes pasar los modificadores extraídos con alcance a los elementos secundarios directos de igual alcance. Consulta la sección Seguridad del alcance en Compose para obtener más información sobre por qué esto es importante:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
Encadenamiento adicional de los modificadores extraídos
Puedes encadenar o agregar aún más las cadenas de modificadores extraídas mediante una llamada a la función .then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
Recuerda que el orden de los modificadores es importante.
Más información
Proporcionamos una lista completa de modificadores, con sus parámetros y alcances.
Para obtener más información sobre cómo usar modificadores, puedes consultar los diseños básicos en el codelab de Compose o consultar el repositorio Now in Android.
Para más información sobre los modificadores personalizados y cómo crearlos, consulta la documentación sobre Diseños personalizados: Cómo usar el modificador de diseño.
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Conceptos básicos sobre el diseño de Compose
- Acciones del editor {:#editor-actions}
- Diseños personalizados {:#custom-layouts }