A subspace is a partition of 3D space within your app where you can place 3D models, build 3D layouts, and add depth to otherwise 2D content. A subspace is rendered only when spatialization is enabled. In Home Space or on non-XR devices, any code within that subspace is ignored.
For more information about spatial layouts and the components you can use within a subspace, see spatialized components.
About subspace hierarchies
The top-level Subspace is the outermost subspace invoked by your app.
Each call to a Subspace method creates a new, independent Spatial UI
hierarchy. It doesn't inherit the spatial position, orientation, or scale of any
parent Subspace it is nested within.
To create an embedded or nested Subspace within a SpatialPanel, Orbiter,
SpatialPopup, or other component, use PlanarEmbeddedSubspace.
PlanarEmbeddedSubspace has two key differences from Subspace:
- They participate in the 2D layout in which they are invoked. This means that the height and width of the subspace will be constrained by the height and width of its 2D parent layout.
- They behave as children of the entity they're invoked in. This means that,
if you call a subspace composable nested inside of a
SpatialPanel, that subspace is a child of theSpatialPanelit's called in.
These behaviors of PlanarEmbeddedSubspace enable capabilities such as:
- Moving the child with the parent entity
- Offsetting the location of the child using the offset
SubspaceModifier - Presenting a 3D object that hovers above your 2D UI and matches the height and width of the appropriate space in the 2D layout
Adapt layouts for a subspace
On Android XR, your app's layout is bound to the VolumeConstraints of
Subspace in Full Space Mode by default. Because of this, you should
consider the amount of visible space available to the user and adjust your
layout accordingly. The recommendedContentBoxInFullSpace provides the
specific dimensions for the bounding box inside the ActivitySpace so that
content can be placed within the user's field of view.
Your app's primary content should fit within this box. If you have content that
must exceed the recommended bounds, consider a layout that encourages users to
explore the space by moving their head. The default constraint of the
recommendedContentBoxInFullSpace can be overridden by applying a custom
size-based modifier such as SubspaceModifier.requiredSizeIn. For unbounded
behavior, set allowUnboundedSubspace = true.
Call recommendedContentBoxInFullSpace using the current Session to
get these specific dimensions as needed. See the following example:
val session = LocalSession.current session?.scene?.activitySpace?.recommendedContentBoxInFullSpace
Add a subspace to your app
The following code example shows how to add Subspace and
PlanarEmbeddedSubspace to your 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 {} } }
See the full reference documentation on Subspace and
PlanarEmbeddedSubspace for more details.