@Composable: qué es, anotación Compose y ámbito de aplicación

Autor: IT Sectr Publicado: 2026-06-27 Tiempo de lectura: 8 min

La anotación @Composable es un elemento fundamental de Jetpack Compose que convierte una función Kotlin ordinaria en un bloque de construcción declarativo de la interfaz de usuario. Sin esta anotación, es imposible crear cualquier pantalla en el desarrollo moderno de Android. Según Google Android Developers, 2026, más del 80% de los proyectos nuevos en Kotlin usan Compose para construir la UI, y @Composable es la anotación más utilizada en el ecosistema.

Puntos Clave

  • @Composable — una anotación de Kotlin que permite a una función describir la UI de forma declarativa
  • Las funciones Composable solo pueden llamar a otras funciones Composable, respetando el contexto de composición
  • El reinicio de las funciones Composable ocurre cuando cambian los parámetros de entrada o el estado
  • El orden de llamada de las funciones Composable no está garantizado — Compose optimiza la reconstrucción de la UI
  • La nomenclatura de las funciones Composable sigue la convención PascalCase, como cualquier componente en Compose

Qué es @Composable en Jetpack Compose

@Composable es una anotación del lenguaje Kotlin que marca una función como destinada a describir la interfaz de usuario en el framework Jetpack Compose. Cuando el compilador de Kotlin encuentra esta anotación, genera código adicional que permite que la función funcione en el contexto de composición — el sistema de gestión del árbol de UI.

La anotación @Composable fue presentada por Google en 2021 junto con la primera versión estable de Jetpack Compose 1.0. Antes de su aparición, el desarrollo de interfaces en Android se realizaba exclusivamente mediante marcado XML y el sistema View. @Composable cambió radicalmente el enfoque: en lugar de describir la UI en un archivo de marcado separado, el desarrollador escribe la interfaz directamente en Kotlin.

La principal diferencia entre @Composable y las funciones Kotlin ordinarias es la capacidad de leer y reaccionar a los cambios de estado. Cuando una variable que lee una función Composable cambia su valor, el sistema programa automáticamente un reinicio (recomposición) de esa función. Esto libera al desarrollador de actualizar manualmente la UI mediante findViewById y setText.

La mecánica interna de @Composable se basa en el concepto de slot — un área de memoria especial que se asigna a cada función dentro de la composición. Este slot almacena los valores pasados a la función, así como la información de servicio necesaria para la comparación en llamadas posteriores.

Cómo declarar una función Composable

Para declarar una función Composable, basta con añadir la anotación @Composable antes de la palabra clave fun. La función debe estar en un paquete que importe la anotación desde androidx.compose.runtime. Se recomienda escribir el nombre de la función con mayúscula inicial — esta es una convención ampliamente aceptada en la comunidad de Compose que distingue visualmente los componentes de UI de las funciones ordinarias.

kotlin
import androidx.compose.runtime.Composable

@Composable
fun Greeting(name: String) {
    var count by remember { mutableStateOf(0) }
    Column {
        Text("¡Hola, $name!")
        Button(onClick = { count++ }) {
            Text("Pulsado $count veces")
        }
    }
}

Los parámetros de una función Composable pueden ser cualquier cosa — tipos primitivos, cadenas, lambdas e incluso otras funciones Composable pasadas a través de Slot API. Se recomienda hacer los parámetros inmutables (val) para evitar efectos secundarios durante la recomposición. Todos los datos mutables deben gestionarse a través de los mecanismos de estado de Compose.

Las funciones Composable no pueden devolver valores arbitrarios como las funciones regulares — su única tarea es construir o actualizar un fragmento del árbol de UI. Sin embargo, existen patrones especiales como State Hoisting, donde una función Compose acepta estado y callbacks a través de parámetros, permaneciendo pura y reutilizable.

Reglas de las funciones Composable en Kotlin

El sistema Compose impone varias restricciones estrictas sobre cómo deben verse y comportarse las funciones Composable. La primera regla: una función Composable solo puede llamar a otras funciones Composable o funciones regulares que no tengan efectos secundarios. Esto garantiza la previsibilidad de la composición y el correcto funcionamiento de las optimizaciones de Compose.

La segunda regla se refiere al orden de ejecución. Compose tiene derecho a llamar a las funciones Composable en cualquier orden, por lo que el código en el cuerpo de dicha función no debe depender de la secuencia de llamada de las funciones vecinas. Cada función Composable debe ser autosuficiente al nivel de su posición en el árbol de UI.

La tercera regla — prohibición de efectos secundarios dentro del cuerpo de una función Composable. Operaciones como escribir en una base de datos, enviar solicitudes de red o modificar variables externas solo deben realizarse dentro de efectos especiales: LaunchedEffect, DisposableEffect o SideEffect. Violar esta regla conduce a un comportamiento impredecible durante las recomposiciones.

La cuarta regla: las funciones Composable deben ser idempotentes. Llamarlas de nuevo con los mismos argumentos debe producir la misma UI. Este requisito es necesario para el correcto funcionamiento de la optimización skipping, donde Compose omite redibujar funciones cuyos datos de entrada no han cambiado.

kotlin
// Correcto: función Composable pura sin efectos secundarios
@Composable
fun UserCard(user: User, onClick: () -> Unit) {
    Card(modifier = Modifier.clickable { onClick() }) {
        Text(text = user.name)
    }
}

// Incorrecto: efecto secundario dentro del cuerpo
@Composable
fun WrongCard(userId: String) {
    // val result = viewModel.loadUser(userId)  // NO PERMITIDO
    Text("Cargando...")
}

Ejemplos de uso de @Composable

Veamos un ejemplo práctico de creación de una pantalla de perfil usando la anotación @Composable. Aquí demostramos la combinación de múltiples funciones Composable, el trabajo con estado y modificadores — elementos clave de cualquier diseño Compose.

kotlin
@Composable
fun ProfileScreen(userId: String) {
    var isFollowed by remember { mutableStateOf(false) }

    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        ProfileHeader(userId = userId)
        Spacer(modifier = Modifier.height(16.dp))
        StatsRow(posts = 42, followers = 1280)
        Spacer(modifier = Modifier.height(24.dp))
        FollowButton(
            isFollowed = isFollowed,
            onToggle = { isFollowed = !isFollowed }
        )
    }
}

@Composable
fun ProfileHeader(userId: String) {
    Row(verticalAlignment = Alignment.CenterVertically) {
        AsyncImage(model = "https://example.com/avatars/$userId",
            contentDescription = "User avatar")
        Spacer(modifier = Modifier.width(12.dp))
        Text(text = "Usuario #$userId", style = MaterialTheme.typography.headlineMedium)
    }
}

@Composable
fun StatsRow(posts: Int, followers: Int) {
    Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
        StatItem("Posts", posts)
        StatItem("Followers", followers)
    }
}

@Composable
fun StatItem(label: String, value: Int) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "$value", style = MaterialTheme.typography.headlineSmall)
        Text(text = label, style = MaterialTheme.typography.bodySmall)
    }
}

En el ejemplo, cada función Composable es responsable de su parte de la pantalla: ProfileScreen gestiona el estado general y la composición de las funciones hijas, ProfileHeader muestra el avatar y el nombre, y StatsRow muestra un bloque de estadísticas. Este enfoque sigue el principio de responsabilidad única y simplifica la reutilización de componentes.

Tipos de funciones Composable y su propósito

En Jetpack Compose, existen tres tipos principales de funciones Composable. El primer tipo — contenedores (Row, Column, Box, LazyColumn) — determina la disposición de los elementos hijos. El segundo tipo — elementos de visualización (Text, Image, Icon, Button) — renderizan componentes de UI específicos. El tercer tipo — funciones Composable personalizadas — combinan componentes integrados en bloques reutilizables.

Los contenedores se diferencian de los elementos regulares en que aceptan una lambda content — el último parámetro de tipo @Composable () -> Unit. Este mecanismo permite construir árboles de UI anidados: cada contenedor genera una composición hija con su propio contexto y área de memoria.

Las funciones Composable personalizadas se dividen en dos subtipos: inteligentes (smart) y tontas (dumb). Las funciones inteligentes gestionan el estado y la lógica — contienen llamadas a remember, LaunchedEffect y otras API de Compose. Las funciones tontas reciben todos los datos a través de parámetros y solo los muestran. La separación en componentes inteligentes y tontos mejora la testabilidad y la reutilización del código.

TipoEjemploPropósito
ContenedorColumn, Row, BoxGestión de la disposición de elementos hijos
ElementoText, Image, ButtonVisualización de contenido y manejo de entrada
PersonalizadoProfileCard, UserListCombinación de componentes estándar

@Composable y reutilización de componentes

La principal ventaja de la anotación @Composable es la capacidad de crear componentes de UI reutilizables sin herencia ni jerarquías complejas de clases. A diferencia del sistema View, donde cada elemento personalizado requería crear una clase Java con constructores, un componente Composable es simplemente una función Kotlin con parámetros.

Para garantizar la reutilización, se utiliza el patrón Slot API, donde una función Composable acepta lambdas content para diferentes áreas de su diseño. Por ejemplo, un componente Card puede aceptar content separado para el encabezado, el cuerpo y el pie, lo que lo hace universal para cualquier pantalla de la aplicación.

Los modificadores (Modifier) juegan un papel clave en la reutilización: permiten configurar paddings, tamaños, clics y animaciones sin cambiar el componente en sí. Se recomienda pasar siempre Modifier como parámetro de una función Composable con un valor por defecto: Modifier = Modifier — esta es una práctica estándar adoptada en las bibliotecas oficiales de Google.

kotlin
@Composable
fun SectionCard(
    modifier: Modifier = Modifier,
    title: String,
    content: @Composable () -> Unit
) {
    Card(modifier = modifier) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = title, style = MaterialTheme.typography.titleMedium)
            Spacer(modifier = Modifier.height(8.dp))
            content()
        }
    }
}

Gracias a Slot API, el componente SectionCard se puede usar en diferentes pantallas con diferentes contenidos — formularios, listas, bloques de texto. La combinación de modificadores y Slot API hace que los componentes Compose sean extremadamente flexibles sin perder la seguridad de tipos que proporciona Kotlin.

Preguntas Frecuentes

¿En qué se diferencia @Composable de una función Kotlin ordinaria?

Una función @Composable se ejecuta en el contexto de composición y puede leer el estado, reiniciándose automáticamente cuando este cambia. Las funciones Kotlin ordinarias no tienen acceso a los mecanismos de seguimiento de estado ni participan en la construcción del árbol de UI.

¿Se puede llamar a una función Composable desde una función normal?

No, las funciones Composable solo se pueden llamar desde otras funciones Composable, ya que se requiere un contexto de composición especial. Para integrar código Compose con Kotlin normal, se utiliza el método setContent { } en Activity o ComposeView en el sistema View.

¿Por qué las funciones Composable se escriben con mayúscula?

Esta es una convención de nomenclatura adoptada en la comunidad de Compose. La mayúscula inicial distingue visualmente los componentes de UI de las funciones ordinarias, siguiendo las reglas de nomenclatura de clases. No es un requisito del compilador, sino una práctica recomendada en la documentación de Google.

¿Cuántas funciones Composable puede haber en una pantalla?

No hay límites en la cantidad. En la práctica, una pantalla grande puede contener 50–100 funciones Composable, incluyendo componentes integrados (Text, Button) y personalizados. Compose optimiza el árbol de funciones y solo ejecuta aquellas cuyos datos de entrada han cambiado.

¿Puede una función Composable devolver un valor?

Normalmente las funciones Composable devuelven Unit, ya que su tarea es construir la UI. Sin embargo, existen funciones especializadas como remember y derivedStateOf que están marcadas con @Composable y devuelven valores. Esta es una excepción, no la regla.

Resumen

  • @Composable — anotación para descripción declarativa de UI en Jetpack Compose
  • Las funciones Composable se llaman solo dentro de otras funciones Composable en un contexto especial
  • Idempotencia — cada ejecución repetida con los mismos argumentos produce la misma UI
  • Efectos secundarios prohibidos en el cuerpo de la función — solo a través de LaunchedEffect y SideEffect
  • Slot API y Modifier garantizan la reutilización de componentes sin herencia
  • Funciones contenedoras (Row, Column, LazyColumn) aceptan lambdas content para elementos anidados
  • Recomendación: pasar Modifier como parámetro de cada función Composable personalizada con un valor por defecto

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también