Agrega un subespacio a tu app

Dispositivos XR aplicables
Esta guía te ayuda a crear experiencias para estos tipos de dispositivos de XR.
Auriculares XR
Lentes de RE con cable

Un subespacio es una partición de espacio 3D dentro de tu app en la que puedes colocar modelos 3D, compilar diseños 3D y agregar profundidad a contenido que, de otra forma, es 2D. Un subespacio solo se renderiza cuando se habilita la espacialización. En el espacio principal o en dispositivos que no son de XR, se ignora cualquier código dentro de ese subespacio.

Puedes usar elementos componibles de subespacio, como SpatialPanel, SpatialRow y SpatialColumn, para crear tu diseño y colocar contenido 2D en el espacio 3D. Para colocar contenido en 3D, usa el elemento SceneCoreEntity de Subspace Composable adecuado para los modelos en 3D y SpatialExternalSurface para las imágenes estereoscópicas. Algunos componentes de XR, como Orbiter o SpatialDialog, son elementos componibles 2D estándar que se pueden usar en cualquier parte de la jerarquía de la IU 2D, pero se debe invocar un SubspaceComposable en el subespacio de la app. Para ello, usa el elemento Subspace componible del subespacio.

Acerca de las jerarquías de subespacios

El Subspace de nivel superior es el subespacio más externo que invoca tu app. Cada llamada a un Subspace crea una jerarquía de IU espacial nueva e independiente. No hereda la posición espacial, la orientación ni la escala de ningún Subspace principal dentro del que esté anidado.

Para crear un Subspace incorporado o anidado dentro de un SpatialPanel, Orbiter, SpatialPopup o algún otro componente, usa PlanarEmbeddedSubspace.

PlanarEmbeddedSubspace tiene dos diferencias clave con respecto a Subspace:

  • Participan en el diseño 2D en el que se invocan. Esto significa que la altura y el ancho del subespacio estarán restringidos por la altura y el ancho de su diseño principal en 2D.
  • Se comportan como elementos secundarios de la entidad en la que se invocan. Esto significa que, si llamas a un elemento componible de subespacio anidado dentro de un SpatialPanel, ese subespacio es secundario del SpatialPanel en el que se llama.

Estos comportamientos de PlanarEmbeddedSubspace habilitan capacidades como las siguientes:

  • Cómo mover el elemento secundario con la entidad principal
  • Cómo desplazar la ubicación del elemento secundario con el desplazamiento SubspaceModifier
  • Presentar un objeto 3D que se desplaza sobre la IU 2D y coincide con la altura y el ancho del espacio adecuado en el diseño 2D

Cómo adaptar diseños para un subespacio

En Android XR, el diseño de tu app está vinculado al VolumeConstraints de Subspace en el modo de espacio completo de forma predeterminada. Por este motivo, debes tener en cuenta la cantidad de espacio visible disponible para el usuario y ajustar tu diseño según corresponda. El recommendedContentBoxInFullSpace proporciona las dimensiones específicas del cuadro de límite dentro del ActivitySpace para que el contenido se pueda colocar dentro del campo visual del usuario.

El contenido principal de tu app debe caber dentro de este cuadro. Si tienes contenido que debe exceder los límites recomendados, considera un diseño que aliente a los usuarios a explorar el espacio moviendo la cabeza. La restricción predeterminada de recommendedContentBoxInFullSpace se puede anular si se aplica un modificador personalizado basado en el tamaño, como SubspaceModifier.requiredSizeIn. Para el comportamiento sin límites, establece allowUnboundedSubspace = true.

Llama a recommendedContentBoxInFullSpace con la Session actual para obtener estas dimensiones específicas según sea necesario. Observa el siguiente ejemplo:

val session = LocalSession.current
session?.scene?.activitySpace?.recommendedContentBoxInFullSpace

Cómo agregar un subespacio a tu app

En el siguiente ejemplo de código, se muestra cómo agregar Subspace y PlanarEmbeddedSubspace a tu app:

setContent {
    // This is a top-level subspace
    Subspace {
        SpatialPanel {
            MyComposable()
        }
    }
}

@Composable
private fun MyComposable() {
    Row {
        PrimaryPane()
        SecondaryPane()
    }
}

@Composable
private fun PrimaryPane() {
    // This is an embedded subspace, because PrimaryPane is in a SpatialPanel
    // and that SpatialPanel is in the top-level Subspace
    PlanarEmbeddedSubspace {
        SpatialPanel {}
    }
}

Consulta la documentación de referencia completa sobre Subspace y PlanarEmbeddedSubspace para obtener más detalles.