Développer une UI avec Jetpack Compose pour XR

Avec Jetpack Compose pour XR, vous pouvez créer de manière déclarative votre UI spatiale et votre mise en page à l'aide de concepts Compose familiers tels que les lignes et les colonnes. Vous pouvez ainsi étendre votre UI Android existante dans un espace 3D ou créer des applications 3D immersives entièrement nouvelles.

Si vous spatialisez une application Android basée sur les vues, plusieurs options de développement s'offrent à vous. Vous pouvez utiliser des API d'interopérabilité, Compose et Views ensemble, ou travailler directement avec la bibliothèque SceneCore. Pour en savoir plus, consultez notre guide sur l'utilisation des vues.

À propos des sous-espaces et des composants spatialisés

Lorsque vous écrivez votre application pour Android XR, il est important de comprendre les concepts d'sous-espace et de composants spatialisés.

À propos du sous-espace

Lorsque vous développez pour Android XR, vous devez ajouter un sous-espace à votre application ou à votre mise en page. Un sous-espace est une partition de l'espace 3D de votre application dans laquelle vous pouvez placer du contenu 3D, créer des mises en page 3D et ajouter de la profondeur à du contenu 2D. Un sous-espace n'est affiché que lorsque la spatialisation est activée. Dans l'espace de la maison ou sur les appareils non XR, tout code de ce sous-espace est ignoré.

Il existe deux façons de créer un sous-espace:

  • setSubspaceContent: cette fonction crée un sous-espace au niveau de l'application. Vous pouvez l'appeler dans votre MainActivity de la même manière que vous utilisez setContent. Un sous-espace au niveau de l'application est illimité en hauteur, largeur et profondeur, ce qui fournit essentiellement un canevas infini pour le contenu spatial.
  • Subspace: ce composable peut être placé n'importe où dans la hiérarchie de l'UI de votre application. Vous pouvez ainsi conserver les mises en page pour l'UI 2D et l'UI spatiale sans perdre de contexte entre les fichiers. Cela permet de partager plus facilement des éléments tels que l'architecture d'application existante entre la RA et d'autres facteurs de forme, sans avoir à hisser l'état dans l'ensemble de l'arborescence de l'UI ni à réarchitecturer votre application.

Pour en savoir plus, consultez la section Ajouter un sous-espace à votre application.

À propos des composants spatialisés

Composables de sous-espace: ces composants ne peuvent être affichés que dans un sous-espace. Ils doivent être inclus dans Subspace ou setSubspaceContent avant d'être placés dans une mise en page 2D. Un SubspaceModifier vous permet d'ajouter des attributs tels que la profondeur, le décalage et le positionnement à vos composables d'espaces sous-jacents.

  • Remarque concernant les modificateurs de sous-espace: Veillez à respecter l'ordre des API SubspaceModifier.
    • Le décalage doit se produire en premier dans une chaîne de modificateurs
    • Les éléments mobiles et redimensionnables doivent être les derniers à être définis.
    • La rotation doit être appliquée avant le scaling.

Les autres composants spatialisés n'ont pas besoin d'être appelés dans un sous-espace. Ils se composent d'éléments 2D conventionnels encapsulés dans un conteneur spatial. Ces éléments peuvent être utilisés dans des mises en page 2D ou 3D s'ils sont définis pour les deux. Lorsque la spatialisation n'est pas activée, les éléments spatialisés sont ignorés et leurs homologues 2D sont utilisés.

Créer un panneau spatial

Un SpatialPanel est un composable d'espace sous-jacent qui vous permet d'afficher le contenu de l'application. Par exemple, vous pouvez afficher la lecture vidéo, des images fixes ou tout autre contenu dans un panneau spatial.

Exemple de panneau d'interface utilisateur spatial

Vous pouvez utiliser SubspaceModifier pour modifier la taille, le comportement et le positionnement du panneau spatial, comme illustré dans l'exemple suivant.

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
        )
    }
}

Points clés concernant le code

  • Remarque concernant les modificateurs de sous-espace: Veillez à respecter l'ordre des API SubspaceModifier.
    • Le décalage doit apparaître en premier dans une chaîne de modificateurs.
    • Les modificateurs mobiles et redimensionnables doivent être les derniers.
    • La rotation doit être appliquée avant la mise à l'échelle.
  • Étant donné que les API SpatialPanel sont des composables de sous-espace, vous devez les appeler dans Subspace ou setSubspaceContent. Les appeler en dehors d'un sous-espace génère une exception.
  • Autorisez l'utilisateur à redimensionner ou à déplacer le panneau en ajoutant des SubspaceModifier .movable ou .resizable.
  • Pour en savoir plus sur le dimensionnement et le positionnement, consultez nos conseils de conception pour les panneaux spatiaux. Pour en savoir plus sur l'implémentation du code, consultez notre documentation de référence.

Créer un orbiteur

Un orbiteur est un composant d'UI spatial. Il est conçu pour être associé à un panneau spatial correspondant et contient des éléments d'action de navigation et contextuelle liés à ce panneau spatial. Par exemple, si vous avez créé un panneau spatial pour afficher du contenu vidéo, vous pouvez ajouter des commandes de lecture vidéo dans un orbiteur.

Exemple d'orbiteur

Comme illustré dans l'exemple suivant, appelez un orbiteur dans un SpatialPanel pour encapsuler les commandes utilisateur telles que la navigation. Vous les extrayez ainsi de votre mise en page 2D et les associez au panneau spatial en fonction de votre configuration.

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
                )
            }
        }
    }
}

Points clés concernant le code

  • Remarque concernant les modificateurs de sous-espace: Veillez à respecter l'ordre des API SubspaceModifier.
    • Le décalage doit se produire en premier dans une chaîne de modificateurs
    • Les éléments mobiles et redimensionnables doivent être les derniers à être définis.
    • La rotation doit être appliquée avant le scaling.
  • Étant donné que les orbiteurs sont des composants d'UI spatiaux, le code peut être réutilisé dans des mises en page 2D ou 3D. Dans une mise en page 2D, votre application n'affiche que le contenu dans l'orbiteur et ignore l'orbiteur lui-même.
  • Pour en savoir plus sur l'utilisation et la conception des orbiteurs, consultez nos conseils de conception.

Ajouter plusieurs panneaux spatiaux à une mise en page spatiale

Vous pouvez créer plusieurs panneaux spatiaux et les placer dans une mise en page spatiale à l'aide de SpatialRow, SpatialColumn, SpatialBox et SpatialLayoutSpacer.

Exemple de plusieurs panneaux spatiaux dans une mise en page spatiale

L'exemple de code suivant montre comment procéder.

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
        )
    }
}

Points clés concernant le code

  • SpatialRow, SpatialColumn, SpatialBox et SpatialLayoutSpacer sont tous des composables de sous-espace et doivent être placés dans un sous-espace.
  • Utilisez SubspaceModifier pour personnaliser votre mise en page.
  • Pour les mises en page comportant plusieurs panneaux sur une ligne, nous vous recommandons de définir un rayon de courbe de 825 dp à l'aide d'un SubspaceModifier afin que les panneaux entourent l'utilisateur. Pour en savoir plus, consultez nos consignes de conception.

Utiliser un volume pour placer un objet 3D dans votre mise en page

Pour placer un objet 3D dans votre mise en page, vous devez utiliser un composable d'espace sous-jacent appelé volume. Voici un exemple de la procédure à suivre.

Exemple d'objet 3D dans une mise en page

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
                }
            }
        }
    }
}

Points clés concernant le code

  • Remarque concernant les modificateurs de sous-espace: Veillez à respecter l'ordre des API SubspaceModifier.
    • Le décalage doit se produire en premier dans une chaîne de modificateurs.
    • Les éléments mobiles et redimensionnables doivent être les derniers à être définis.
    • La rotation doit être appliquée avant le scaling.
  • Consultez Ajouter du contenu 3D pour découvrir comment charger du contenu 3D dans un volume.

Ajouter d'autres composants d'interface utilisateur spatial

Les composants d'interface utilisateur spatiale peuvent être placés n'importe où dans la hiérarchie de l'interface utilisateur de votre application. Ces éléments peuvent être réutilisés dans votre UI 2D, et leurs attributs spatiaux ne seront visibles que lorsque les fonctionnalités spatiales seront activées. Vous pouvez ainsi ajouter une élévation aux menus, aux boîtes de dialogue et à d'autres composants sans avoir à écrire votre code deux fois. Consultez les exemples d'UI spatiale suivants pour mieux comprendre comment utiliser ces éléments.

Composant d'interface utilisateur

Lorsque la spatialisation est activée

Dans un environnement 2D

SpatialDialog

Le panneau est légèrement repoussé en arrière dans la profondeur de champ pour afficher une boîte de dialogue surélevée.

Revenir en mode 2D Dialog

SpatialPopUp

Le panneau recule légèrement en profondeur pour afficher un pop-up surélevé.

Retourne à une PopUp 2D.

SpatialElevation

SpatialElevationLevel peut être défini pour ajouter une élévation.

Émissions sans élévation spatiale.

SpatialDialog

Voici un exemple de boîte de dialogue qui s'ouvre après un court délai. Lorsque SpatialDialog est utilisé, la boîte de dialogue s'affiche à la même profondeur Z que le panneau spatial, et le panneau est repoussé de 125 dp lorsque la spatialisation est activée. SpatialDialog peut toujours être utilisé lorsque la spatialisation n'est pas activée non plus, et il revient à son homologue 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")
               }
           }
       }
   }
}

Points clés concernant le code

Créer des panneaux et des mises en page personnalisés

Pour créer des panneaux personnalisés non compatibles avec Compose pour XR, vous pouvez travailler directement avec PanelEntities et le graphique de scène à l'aide des API SceneCore.

Voir aussi