Con Jetpack Compose para XR, puedes compilar de forma declarativa tu IU y diseño espacial con conceptos conocidos de Compose, como filas y columnas. Esto te permite expandir tu IU de Android existente al espacio 3D o compilar aplicaciones 3D envolventes completamente nuevas.
Si espacializas una app existente basada en objetos View de Android, tienes varias opciones de desarrollo. Puedes usar APIs de interoperabilidad, usar Compose y Views juntos, o trabajar directamente con la biblioteca de SceneCore. Consulta nuestra guía para trabajar con vistas para obtener más detalles.
Información acerca de los subespacios y los componentes espacializados
Cuando escribes tu app para Android XR, es importante comprender los conceptos de subespacio y componentes espacializados.
Información acerca del subespacio
Cuando desarrolles para Android XR, deberás agregar un subespacio a tu app o diseño. Un subespacio es una partición del espacio 3D dentro de tu app en la que puedes colocar contenido 3D, compilar diseños 3D y agregar profundidad a contenido que, de otro modo, sería 2D. Un subespacio solo se renderiza cuando la espacialización está habilitada. En Home Space o en dispositivos que no son XR, se ignora cualquier código dentro de ese subespacio.
Existen dos formas de crear un subespacio:
setSubspaceContent()
: Esta función crea un subespacio a nivel de la app. Se puede llamar a esta función en tu actividad principal de la misma manera que usassetContent()
. Un subespacio a nivel de la app no tiene límites de altura, ancho ni profundidad, lo que proporciona un lienzo infinito para el contenido espacial.Subspace
: Este elemento componible se puede colocar en cualquier lugar dentro de la jerarquía de la IU de tu app, lo que te permite mantener diseños para la IU 2D y espacial sin perder el contexto entre los archivos. Esto facilita compartir elementos como la arquitectura de la app existente entre XR y otros factores de forma sin necesidad de elevar el estado a través de todo el árbol de la IU ni de rediseñar la arquitectura de tu app.
Para obtener más información, consulta Cómo agregar un subespacio a tu app.
Información acerca de los componentes espacializados
Elementos componibles de subespacio: Estos componentes solo se pueden renderizar en un subespacio.
Deben encerrarse en Subspace
o setSubspaceContent
antes de colocarse en un diseño 2D. Un SubspaceModifier
te permite agregar atributos como profundidad, desplazamiento y posicionamiento a tus elementos componibles de subespacio.
Otros componentes espacializados no requieren que se los llame dentro de un subespacio. Consisten en elementos 2D convencionales unidos en un contenedor espacial. Estos elementos se pueden usar en diseños 2D o 3D si se definen para ambos. Cuando la espacialización no está habilitada, se ignorarán sus componentes espacializados y se usarán sus contrapartes en 2D.
Crea un panel espacial
Un SpatialPanel
es un elemento componible de subespacio que te permite mostrar contenido de la app. Por ejemplo, puedes mostrar la reproducción de video, imágenes fijas o cualquier otro contenido en un panel espacial.
Puedes usar SubspaceModifier
para cambiar el tamaño, el comportamiento y la posición del panel espacial, como se muestra en el siguiente ejemplo.
Subspace {
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.movable()
.resizable()
) {
SpatialPanelContent()
}
}
// 2D content placed within the spatial panel
@Composable
fun SpatialPanelContent(){
Box(
Modifier
.background(color = Color.Black)
.height(500.dp)
.width(500.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "Spatial Panel",
color = Color.White,
fontSize = 25.sp
)
}
}
Puntos clave sobre el código
- Debido a que las APIs de
SpatialPanel
son componibles de subespacio, debes llamarlas dentro deSubspace
osetSubspaceContent
. Si los llamas fuera de un subespacio, se genera una excepción. - Agrega los modificadores
movable
oresizable
para permitir que el usuario cambie el tamaño del panel o lo mueva. - Consulta nuestra guía de diseño de paneles espaciales para obtener detalles sobre el tamaño y el posicionamiento. Consulta nuestra documentación de referencia para obtener más información sobre la implementación de códigos.
Crea una órbita
Un orbitador es un componente de IU espacial. Está diseñado para adjuntarse a un panel espacial, un diseño o alguna otra entidad correspondiente. Por lo general, un orbitador contiene elementos de acción contextuales y de navegación relacionados con la entidad a la que está anclado. Por ejemplo, si creaste un panel espacial para mostrar contenido de video, puedes agregar controles de reproducción de video dentro de un orbitador.
Como se muestra en el siguiente ejemplo, llama a un orbitador dentro del diseño 2D en un SpatialPanel
para unir los controles del usuario, como la navegación. De esta manera, se extraen de tu diseño 2D y se adjuntan al panel espacial según tu configuración.
setContent {
Subspace {
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.movable()
.resizable()
) {
SpatialPanelContent()
OrbiterExample()
}
}
}
//2D content inside Orbiter
@Composable
fun OrbiterExample() {
Orbiter(
position = OrbiterEdge.Bottom,
offset = 96.dp,
alignment = Alignment.CenterHorizontally
) {
Surface(Modifier.clip(CircleShape)) {
Row(
Modifier
.background(color = Color.Black)
.height(100.dp)
.width(600.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Orbiter",
color = Color.White,
fontSize = 50.sp
)
}
}
}
}
Puntos clave sobre el código
- Debido a que los orbitadores son componentes espaciales de la IU, el código se puede reutilizar en diseños 2D o 3D. En un diseño 2D, tu app renderiza solo el contenido dentro del orbitador y lo ignora.
- Consulta nuestra guía de diseño para obtener más información sobre cómo usar y diseñar orbitadores.
Cómo agregar varios paneles espaciales a un diseño espacial
Puedes crear varios paneles espaciales y colocarlos dentro de un diseño espacial con SpatialRow
, SpatialColumn
, SpatialBox
y SpatialLayoutSpacer
.
En el siguiente ejemplo de código, se muestra cómo hacerlo.
Subspace {
SpatialRow {
SpatialColumn {
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Top Left")
}
SpatialPanel(SubspaceModifier.height(200.dp).width(400.dp)) {
SpatialPanelContent("Middle Left")
}
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Bottom Left")
}
}
SpatialColumn {
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Top Right")
}
SpatialPanel(SubspaceModifier.height(200.dp).width(400.dp)) {
SpatialPanelContent("Middle Right")
}
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Bottom Right")
}
}
}
}
@Composable
fun SpatialPanelContent(text: String) {
Column(
Modifier
.background(color = Color.Black)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Panel",
color = Color.White,
fontSize = 15.sp
)
Text(
text = text,
color = Color.White,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
}
}
Puntos clave sobre el código
SpatialRow
,SpatialColumn
,SpatialBox
ySpatialLayoutSpacer
son elementos componibles de subespacio y deben colocarse dentro de un subespacio.- Usa
SubspaceModifier
para personalizar el diseño. - Para diseños con varios paneles en una fila, te recomendamos que establezcas un radio de curva de 825 dp con un
SubspaceModifier
para que los paneles rodeen al usuario. Consulta nuestra guía de diseño para obtener más detalles.
Usa un volumen para colocar un objeto 3D en tu diseño
Para colocar un objeto 3D en tu diseño, deberás usar un elemento componible de subespacio llamado volumen. Este es un ejemplo de cómo hacerlo.
Subspace {
SpatialPanel(
SubspaceModifier.height(1500.dp).width(1500.dp)
.resizable().movable()
) {
ObjectInAVolume(true)
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Welcome",
fontSize = 50.sp,
)
}
}
}
}
@Composable
fun ObjectInAVolume(show3DObject: Boolean) {
val xrCoreSession = checkNotNull(LocalSession.current)
val scope = rememberCoroutineScope()
if (show3DObject) {
Subspace {
Volume(
modifier = SubspaceModifier
.offset(volumeXOffset, volumeYOffset, volumeZOffset) //
Relative position
.scale(1.2f) // Scale to 120% of the size
) { parent ->
scope.launch {
// Load your 3D Object here
}
}
}
}
}
Puntos clave sobre el código
- Consulta Cómo agregar modelos 3D a tu app para comprender mejor cómo cargar contenido 3D dentro de un volumen.
Cómo agregar otros componentes espaciales de la IU
Los componentes de la IU espacial se pueden colocar en cualquier lugar de la jerarquía de la IU de tu aplicación. Estos elementos se pueden volver a usar en tu IU 2D, y sus atributos espaciales solo serán visibles cuando se habiliten las capacidades espaciales. Esto te permite agregar elevación a menús, diálogos y otros componentes sin necesidad de escribir el código dos veces. Consulta los siguientes ejemplos de IU espacial para comprender mejor cómo usar estos elementos.
Componente de IU |
Cuándo se habilita la espacialización |
En el entorno 2D |
---|---|---|
|
El panel se empujará ligeramente hacia atrás en la profundidad en Z para mostrar un diálogo elevado. |
Recurre a 2D |
|
El panel se empujará ligeramente hacia atrás en la profundidad en Z para mostrar una ventana emergente elevada. |
Recurre a un |
|
Se puede configurar |
Muestras sin elevación espacial. |
SpatialDialog
Este es un ejemplo de un diálogo que se abre después de una breve demora. Cuando se usa SpatialDialog
, el diálogo aparece en la misma profundidad en Z que el panel espacial, y el panel se aleja 125 dp cuando se habilita la espacialización. SpatialDialog
también se puede usar cuando la espacialización no está habilitada, en cuyo caso SpatialDialog
recurre a su contraparte en 2D, Dialog
.
@Composable
fun DelayedDialog() {
var showDialog by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
Handler(Looper.getMainLooper()).postDelayed({
showDialog = true
}, 3000)
}
if (showDialog) {
SpatialDialog (
onDismissRequest = { showDialog = false },
SpatialDialogProperties(
dismissOnBackPress = true)
){
Box(Modifier
.height(150.dp)
.width(150.dp)
) {
Button(onClick = { showDialog = false }) {
Text("OK")
}
}
}
}
}
Puntos clave sobre el código
- Este es un ejemplo de
SpatialDialog
. El uso deSpatialPopUp
ySpatialElevation
es muy similar. Consulta nuestra referencia de la API para obtener más detalles.
Crea paneles y diseños personalizados
Para crear paneles personalizados que Compose para XR no admite, puedes trabajar directamente con PanelEntities
y el grafo de escenas con las APIs de SceneCore
.
Cómo anclar orbitadores a diseños espaciales y otras entidades
Puedes fijar un objeto orbitador a cualquier entidad declarada en Compose. Esto implica declarar un orbitador en un diseño espacial de elementos de la IU, como SpatialRow
, SpatialColumn
o SpatialBox
. El orbitador se ancla a la entidad superior más cercana a la que lo declaraste.
El comportamiento del orbitador se determina según dónde lo declares:
- En un diseño 2D unido a un
SpatialPanel
(como se muestra en un fragmento de código anterior), el orbitador se ancla a eseSpatialPanel
. - En un
Subspace
, el orbitador se ancla a la entidad superior más cercana, que es el diseño espacial en el que se declara el orbitador.
En el siguiente ejemplo, se muestra cómo fijar un orbitador a una fila espacial:
Subspace {
SpatialRow {
Orbiter(
position = OrbiterEdge.Top,
offset = EdgeOffset.inner(8.dp),
shape = SpatialRoundedCornerShape(size = CornerSize(50))
) {
Text(
"Hello World!",
style = MaterialTheme.typography.titleLarge,
modifier = Modifier
.background(Color.White)
.padding(16.dp)
)
}
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
) {
Box(
modifier = Modifier
.background(Color.Red)
)
}
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
) {
Box(
modifier = Modifier
.background(Color.Blue)
)
}
}
}
Puntos clave sobre el código
- Cuando declaras un orbitador fuera de un diseño 2D, este se ancla a su entidad superior más cercana. En este caso, el orbitador se ancla a la parte superior del
SpatialRow
en el que se declara. - Los diseños espaciales, como
SpatialRow
,SpatialColumn
ySpatialBox
, tienen entidades sin contenido asociadas. Por lo tanto, un orbitador declarado en un diseño espacial se ancla a ese diseño.
Consulta también
- Cómo agregar modelos 3D a tu app
- Desarrolla una IU para apps basadas en objetos View de Android
- Implementa Material Design para XR