Diseño de postura de mesa con cuadrícula y mediaQuery

Ícono de calificación de 4 estrellas

La posición de mesa en dispositivos plegables divide una sola pantalla en dos áreas de visualización funcionales divididas por el pliegue físico (o la bisagra). La posición de mesa te permite colocar el contenido principal de tu app (como un reproductor de video o un lienzo de juego) en la mitad superior, mientras que posicionas los elementos interactivos (como los controles multimedia o los paneles de control) en la mitad inferior.

Dispositivo plegable en posición de mesa que muestra contenido de video en la pantalla superior y controles de reproducción en la pantalla inferior.
Figura 1. La posición de mesa divide el contenido y los controles interactivos a través del pliegue físico.

Prácticas recomendadas

Para agregar compatibilidad con la posición de mesa a tu app, usa la Grid API para definir un diseño con dos filas y una columna, y aplica la consulta de medios de posición de ventana de mesa.

  • Detecta la posición de mesa de forma reactiva: Usa el elemento componible mediaQuery para observar el estado del dispositivo. Cuando el dispositivo se pliega en posición de mesa (windowPosture == Posture.Tabletop), cambia tu diseño de forma dinámica sin necesidad de reiniciar la actividad ni de controlar el ciclo de vida complejo.
  • Estructura diseños con Grid: Cuando esté en posición de mesa, usa la API de Grid (2 rows, 1 column) para separar claramente el contenido visual principal en la fila superior en la mitad superior de la página y los controles interactivos en la fila inferior en la mitad inferior de la página.
  • Aprovecha la indexación z implícita para superposiciones: En posiciones estándar (no de mesa), asigna varios IDs de área a la misma celda para superponer controles sobre el reproductor. Grid renderiza automáticamente los elementos de atrás hacia adelante en su orden de declaración.
  • Proporciona transiciones fluidas: Asegúrate de que se conserven el estado y las posiciones de desplazamiento cuando se realice la transición entre los diseños estándar de pantalla completa y la posición de mesa.

Ingredientes

  • Grid: Es un contenedor de diseño adaptable que te permite posicionar elementos en filas y columnas configurables, ideal para dividir el contenido en distintas regiones de la pantalla.
  • mediaQuery: Es una API de Jetpack Compose que se usa para consultar la posición de ventana, las clases de tamaño y las características de hardware actuales de la app directamente dentro de tus elementos componibles.

Pasos

Consulta la posición del dispositivo con mediaQuery(). Cuando el dispositivo esté en posición de mesa, organiza el contenido de tu app en una cuadrícula vertical con dos filas y una columna, lo que garantiza que el contenido principal permanezca en la parte superior y que los controles sigan siendo accesibles en la parte inferior.

1. Define las configuraciones de cuadrícula para el modo de mesa

Dentro de una función de componibilidad, define los IDs de área de diseño con una enumeración y configura bloques GridConfigurationScope para las posiciones predeterminada y de mesa.

En defaultConfig, ambas áreas se asignan a la misma celda (row = 1, column = 1). Grid usa la indexación z implícita, en la que los elementos componibles declarados más adelante en el diseño se renderizan sobre los anteriores, lo que permite que el controlador superponga el reproductor sin anidación de contenedor adicional (consulta Superposiciones de elementos de la IU con cuadrícula para obtener más detalles).

enum class VideoPlayerArea { Player, Controller }

object PlayerGridConfig {
    // Default: Single area layout with overlay (controls on top of player)
    val defaultConfig: GridConfigurationScope.() -> Unit = {
        row(1f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1)
        area(areaId = VideoPlayerArea.Controller, row = 1, column = 1)
    }

    // Tabletop: Two rows splitting content across the fold
    val tabletopConfig: GridConfigurationScope.() -> Unit = {
        row(0.5f)
        row(0.5f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1) // Top half above fold
        area(areaId = VideoPlayerArea.Controller, row = 2, column = 1) // Bottom half below fold
    }
}

2. Detecta la posición de mesa y aplica la configuración a la cuadrícula

Usa mediaQuery para seleccionar la configuración activa según windowPosture, pasa config a Grid y vincula el contenido componible a los IDs de área. Declarar VideoPlayerArea.Player antes de VideoPlayerArea.Controller garantiza que, cuando ambos compartan una celda en defaultConfig, los controles se rendericen sobre el reproductor:

val config = mediaQuery {
    when (windowPosture) {
        Posture.Tabletop -> PlayerGridConfig.tabletopConfig
        else -> PlayerGridConfig.defaultConfig
    }
}

Grid(config = config) {
    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Player)
    ) {
        // VideoPlayerContent
    }

    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Controller)
    ) {
        // PlaybackControlsContent
    }
}

Resultados

Si combinas mediaQuery y Grid, tu app detecta de forma dinámica cuando un dispositivo plegable se pliega parcialmente en posición de mesa y ajusta automáticamente su IU en dos áreas de visualización funcionales divididas por el pliegue.

Recursos adicionales