Novedades del producto

Novedades de la versión de agosto de 2026 de Jetpack Compose

Lectura de 5 min
Ver el perfil de Nick Butcher
Nick Butcher Product Manager

Hoy, la versión de agosto de 2026 de Jetpack Compose es estable. Esta versión incluye la versión 1.12 en todos los módulos principales de Compose (consulta la asignación completa del BOM), que introduce APIs visuales enriquecidas, como la compatibilidad con degradados de malla y la amplia gama de colores (WCG), funciones de diseño estructural, como las áreas con nombre en Grid, integración fluida con el Administrador de credenciales de Android y mejoras significativas en las pruebas y el rendimiento.

Para actualizar tu proyecto a la versión de hoy, actualiza la versión de tu BOM de Compose a 2026.08.00:

implementation(platform("androidx.compose:compose-bom:2026.08.00"))

Cambios rotundos

  • AGP y Compile SDK: Compose 1.12 actualiza compileSdk a la API 37, lo que requiere un AGP 9.1.2 como mínimo. Como recordatorio, Compose siempre tendrá como objetivo el compileSdk más reciente. Obtén más información sobre este cambio aquí.
  • Modifier.onFirstVisible() dejó de estar disponible: Migra a Modifier.onVisibilityChanged(), que proporciona un seguimiento más preciso del umbral de visibilidad.

Gráficos

Gradientes de malla

Compose 1.12 presenta MeshGradientPainter para ayudarte a crear degradados de color orgánicos de varios puntos.

meshGradient.gif
val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

Para obtener más información y ejemplos, consulta la documentación.

Amplia gama de colores y compatibilidad con HDR

Las pantallas modernas ofrecen una mayor fidelidad del color y un rango dinámico más alto. En Compose 1.12, se habilitó la compatibilidad completa con la canalización para la amplia gama de colores (P3) y la renderización HDR en los gráficos, la pintura y los sombreadores de Compose. Los colores definidos en espacios de color que no son sRGB (como Display P3) se conservan hasta la renderización de la plataforma sin fijación de color. Los colores volverán a sRGB de forma segura si usan un espacio de color no compatible (p. ej., CieXyz, CieLab o Oklab), si dependen de un espacio de color en una versión de Android no compatible (p. ej., Bt2020Hlg en Android 13 y versiones anteriores) o si la app se ejecuta en Android 9 (API 28) y versiones anteriores.

Otros cambios notables:

  • Se agregó LayerOutsets a GraphicsLayer y Modifier.graphicsLayer, que puedes usar para aumentar los límites visuales de la capa más allá de su tamaño medido. Aplica LayerOutsets para evitar el comportamiento implícito de clipToBounds cuando la capa se promueve a un búfer fuera de pantalla.

Estilos

En Google I/O, compartimos nuestra visión inicial de la API de Styles de Compose, una forma unificada y eficiente de diseñar componentes. Desde entonces, seguimos desarrollando la arquitectura subyacente para garantizar una seguridad de tipos estricta y una corrección predecible, y para admitir la creación de sistemas de diseño personalizados. 

Para asegurarnos de que esta capa fundamental sea correcta, la API seguirá siendo experimental y es posible que se produzcan cambios que interrumpan su funcionamiento. 

Optimizaciones de tiempo de ejecución

Sobrecarga de SideEffect con clave

SideEffect ahora admite argumentos de clave, lo que te permite activar efectos secundarios únicos cada vez que cambian claves específicas. Esto puede generar un mejor rendimiento en comparación con el uso de LaunchedEffect o DisposableEffect cuando no necesitas la corrutina o el bloque de descarte. SideEffect es hasta un 90% más rápido que LaunchedEffect y alrededor de un 20% más rápido que DisposableEffect. Ten en cuenta que SideEffect ejecuta su efecto antes que DisposableEffect y LaunchedEffect, por lo que debes tener cuidado si migras efectos existentes a esta API, en especial para LaunchedEffects que dependen de que se envíen para comenzar después de que se complete el fotograma actual. 

@Composable
fun AnalyticsTracker(userId: String, screenName: String) {
    SideEffect(key1 = userId, key2 = screenName) {
        analytics.logScreenView(userId, screenName)
    }
}

Animación

Transiciones interactivas de dos etapas

  • Nuevos elementos componibles: DeferredAnimatedContent y DeferredAnimatedVisibility permiten crear transiciones agradables de dos etapas, p.ej., para el seguimiento del gesto atrás predictivo.
  • Control manual de la animación: Durante la fase diferida de una transición, las propiedades animadas (como la escala o el desplazamiento) ahora se pueden manipular manualmente en tiempo real (p.ej., para hacer un seguimiento de un gesto de deslizamiento).
  • Transferencia fluida: Una vez que finaliza la fase diferida, el motor de transición toma el control y realiza una transferencia fluida, incluida la transferencia de velocidad, a la transición automática.
  • Compatibilidad con elementos compartidos: Una nueva marca permitTransformDuringDeferredTransition en SharedContentConfig controla si los elementos compartidos se transforman visualmente junto con sus contenedores principales durante la fase de transición diferida.
val state = remember { DeferredTransitionState(initialScreen) }
val transition = rememberDeferredTransition(state)

if (predictiveBackInProgress) {
    state.defer(targetScreen)
} else {
    state.animateTo(targetScreen)
}

transition.DeferredAnimatedContent(
    targetState = targetScreen,
    mutableTransformSpec = {
       MutableContentTransform {
           // Manually manipulate properties during the deferred phase
           initialContentTransform { scale = swipeProgress }
       }
    }
) { screen ->
    ScreenContent(screen)
}

A continuación, se muestran dos demostraciones de casos de uso en los que una animación controlada por gestos se transfiere a una animación activada:

colorCards.gif

Integraciones de texto, entrada y plataformas

Formato de texto editable

Las nuevas APIs ofrecen formato de texto enriquecido para el texto editable en BasicTextField. Ahora puedes aplicar y manipular de forma programática el formato de caracteres y párrafos intercalados con SpanStyle y ParagraphStyle a través del nuevo método addStyle() dentro de un alcance de TextFieldBuffer (como dentro de textFieldState.edit { ... } o un InputTransformation). Además, TextFieldBuffer proporciona las APIs de getSpanStyles() y getParagraphStyles() que devuelven objetos de TrackedRange, lo que te permite leer, actualizar o quitar los estilos aplicados. Para complementar la creación de formato, TextFieldState ahora expone una propiedad textStyles de solo lectura para consultar los estilos activos en los rangos, mientras que TextFieldBuffer proporciona originalTextStyles para inspeccionar el estado del formato antes de una edición. El formato de texto y las anotaciones personalizadas se conservan en los cambios de configuración.

val state = rememberTextFieldState("Formatted text in Compose 1.12")

// Apply bold and color styles to a range of text
state.edit {
    addStyle(
        SpanStyle(fontWeight = FontWeight.Bold, color = Color.Blue),
        start = 0,
        end = 9
    )
}

// Query active styles from TextFieldState
val currentStyles = state.textStyles

Selección de texto

Una nueva API de SelectionState proporciona control y observabilidad programáticos sobre la selección de texto dentro de un SelectionContainer. Elevar un objeto SelectionState a través de rememberSelectionState() y pasarlo a SelectionContainer expone selectedTexts como una lista reactiva de AnnotatedStrings y proporciona métodos como selectAll(), clear(), select(TextRange) y extendSelectionByWord().

Además, usa getSelectableTexts() para recuperar todos los elementos de texto seleccionables en orden de diseño y seleccionar texto en elementos componibles en SelectionContainer con un rango global. 

@Composable
fun ProgrammaticSelectionExample() {
    val selectionState = rememberSelectionState()

    Column {
        Button(
            onClick = { selectionState.selectAll() },
            modifier = Modifier.disableSelectionClearOnTap()
        ) {
            Text("Select All")
        }

        SelectionContainer(state = selectionState) {
            Text("Text content to be selected programmatically.")
        }
    }
}

Integración de Credential Manager

Los campos de texto de Compose ahora se integran de forma nativa con Credential Manager de Android (API 34 y versiones posteriores) a través del framework de Autocompletar (las versiones anteriores a la API 34 se controlan con androidx.credentials library). Si adjuntas la nueva propiedad semántica credentialRequest con CredentialRequestData, las entradas de texto pueden solicitar llaves de acceso, credenciales guardadas o solicitudes de acceso directamente dentro del flujo de entrada del usuario.

@Composable
fun LoginField(textFieldState: TextFieldState) {
    val credentialData = remember {
        CredentialRequestData(
            // Specify Credential Manager request options
        )
    }

    BasicTextField(
        state = textFieldState,
        modifier = Modifier.semantics {
            credentialRequest = credentialData
        }
    )
}

Otros cambios notables:

  • Se agregó compatibilidad con la configuración de variantes de fuentes en fuentes descargables.
  • Se habilitó el desplazamiento automático cuando se arrastra la selección de texto más allá del viewport en SelectionContainer.
  • Se agregó compatibilidad con sonidos de interacción automáticos (clics y navegación por enfoque) a los componentes de Compose, con un nuevo elemento SoundEffectOnInteraction componible para permitir la exclusión. Ten en cuenta que, como consecuencia de este cambio, ahora se debe llamar a los objetos de escucha de clics semánticos desde el subproceso principal, lo que puede afectar una pequeña cantidad de casos de prueba.
  • KeyboardType ahora incluye Date, Time, DateTime y SignedDecimal.
  • BasicSecureTextField ahora usa TextObfuscationMode.System de forma predeterminada, mientras que RevealLastTyped funciona como una anulación absoluta.

Mejoras en el diseño

Áreas con nombre en el diseño de cuadrícula

Ahora es más fácil crear diseños complejos en 2D con áreas con nombre en el componente @Experimental Grid. En lugar de administrar índices numéricos de columnas y filas en todos los elementos, puedes definir regiones semánticas en tu GridConfigurationScope y posicionar elementos componibles por nombre de área.

@OptIn(ExperimentalGridApi::class)
@Composable
fun DashboardLayout() {
    Grid(
        config = {
            area("header", row = 0, column = 0, rowSpan = 1, columnSpan = 2)
            area("sidebar", row = 1, column = 0)
            area("content", row = 1, column = 1)
            gap(16.dp)
        }
    ) {
        HeaderSection(modifier = Modifier.gridItem(areaId = "header"))
        NavigationSidebar(modifier = Modifier.gridItem(areaId = "sidebar"))
        MainContentView(modifier = Modifier.gridItem(areaId = "content"))
    }
}

Para obtener más información, consulta la documentación.

Rendimiento

Al igual que con cada versión, seguimos invirtiendo en el rendimiento de Compose para garantizar que el framework te ayude a compilar apps atractivas y eficientes. En esta versión, nos enfocamos en mejorar el rendimiento del inicio y ahora vemos que el tiempo hasta la visualización inicial (el tiempo que tarda una app en producir su primer fotograma) es comparable al de Views en nuestras comparaciones.

timetoinitialdisplay@2x _v2.png

Actualizaciones de pruebas y herramientas

Sincronización de pruebas

Compose 1.12 presenta nuevas APIs de prueba diseñadas para reducir los tiempos de ejecución de las pruebas y eliminar la inestabilidad durante el muestreo de estados:

  • hasPendingWork: Comprueba de forma pasiva si la IU tiene trabajo pendiente sin adelantar el reloj, lo que es ideal para los bucles de animación manual.
  • runWithoutImplicitWait: Inhabilita temporalmente la sincronización implícita cuando se avanza por los fotogramas del reloj manual (p.ej., pruebas de animación).
@Test
fun testAnimationStateFast() {

composeTestRule.mainClock.autoAdvance = false
    
    while (composeTestRule.hasPendingWork()) {
        composeTestRule.mainClock.advanceTimeByFrame()
        composeTestRule.waitForIdle()
        
        composeTestRule.runOnUiThread {
            composeTestRule.runWithoutImplicitWait {
                // This is most effective when querying multiple nodes in a single frame. 
                // It prevents the redundant synchronization overhead that would 
                // otherwise occur on every individual query.
                val box1 = composeTestRule.onNodeWithTag("Box1").fetchSemanticsNode()
                val box2 = composeTestRule.onNodeWithTag("Box2").fetchSemanticsNode()
                
                assertThat(box1.boundsInRoot.right).isAtMost(box2.boundsInRoot.left)
            }
        }
    }
}

Otros cambios notables:

  • La API de captureToImage ahora te permite capturar una ventana emergente o un diálogo junto con su ancla en un solo mapa de bits.
  • Se agregó onRootWithViewInteraction para limitar el alcance de las búsquedas semánticas de Compose a Views de Android específicas. Esto simplifica las pruebas de IU híbridas, como RecyclerViews, sin requerir etiquetas de prueba únicas en el código de producción.
  • Ahora se pueden aplicar anotaciones @PreviewWrapper a clases @MultiPreview personalizadas, lo que permite configuraciones de vista previa reutilizables (como temas personalizados) en varios componentes.

¡Feliz composición!

Compose 1.12 facilita y hace más expresivo que nunca el desarrollo de apps, con degradados de malla, compatibilidad con una amplia gama de colores, fuentes variables descargables, integración del Administrador de credenciales y herramientas de prueba más rápidas. Como siempre, valoramos tus comentarios, así que no dudes en compartir tus opiniones sobre estos cambios o lo que te gustaría ver a continuación en nuestro rastreador de problemas. ¡Feliz composición!

Escrito por:
Continuar leyendo