Mit Jetpack Compose for XR können Sie Ihre räumliche Benutzeroberfläche und Ihr Layout deklarativ mithilfe bekannter Compose-Konzepte wie Zeilen und Spalten erstellen. So können Sie Ihre vorhandene Android-Benutzeroberfläche in den 3D-Raum erweitern oder völlig neue immersive 3D-Anwendungen erstellen.
Wenn Sie eine vorhandene Android Views-basierte App orten möchten, haben Sie mehrere Entwicklungsoptionen. Sie können Interoperabilitäts-APIs verwenden, Compose und Ansichten zusammen verwenden oder direkt mit der SceneCore-Bibliothek arbeiten. Weitere Informationen finden Sie in unserem Leitfaden zur Arbeit mit Ansichten.
Unterräume und lokalisierte Komponenten
Wenn Sie eine App für Android XR entwickeln, ist es wichtig, die Konzepte Unterraum und räumliche Komponenten zu verstehen.
Subspace
Wenn Sie für Android XR entwickeln, müssen Sie Ihrer App oder Ihrem Layout einen Unterraum hinzufügen. Ein Unterraum ist eine Partition des 3D-Raums in Ihrer App, in der Sie 3D-Inhalte platzieren, 3D-Layouts erstellen und ansonsten 2D-Inhalten Tiefe verleihen können. Ein Unterraum wird nur gerendert, wenn die Spatialisierung aktiviert ist. Im Home Space oder auf Nicht-XR-Geräten wird jeglicher Code in diesem Unterraum ignoriert.
Es gibt zwei Möglichkeiten, einen Unterraum zu erstellen:
setSubspaceContent()
: Mit dieser Funktion wird ein Unterraum auf App-Ebene erstellt. Diese Funktion kann in Ihrer Hauptaktivität auf die gleiche Weise aufgerufen werden wiesetContent()
. Ein Unterraum auf App-Ebene ist in Höhe, Breite und Tiefe unbegrenzt und bietet im Grunde eine unendliche Leinwand für räumliche Inhalte.Subspace
: Diese Komponente kann überall in der UI-Hierarchie Ihrer App platziert werden. So können Sie Layouts für 2D- und räumliche UIs beibehalten, ohne den Kontext zwischen den Dateien zu verlieren. So können Sie z. B. die vorhandene App-Architektur zwischen XR und anderen Formfaktoren teilen, ohne den Status durch den gesamten UI-Baum hochladen oder Ihre App neu entwerfen zu müssen.
Weitere Informationen finden Sie unter Ihrer App einen Unterbereich hinzufügen.
Informationen zu lokalisierten Komponenten
Subspace-Kompositionen: Diese Komponenten können nur in einem Unterbereich gerendert werden.
Sie müssen in Subspace
oder setSubspaceContent
eingeschlossen sein, bevor sie in ein 2D-Layout eingefügt werden können. Mit einem SubspaceModifier
können Sie Ihren Subspace-Kompositionen Attribute wie Tiefe, Offset und Position hinzufügen.
Andere lokalisierte Komponenten müssen nicht innerhalb eines Unterraums aufgerufen werden. Sie bestehen aus herkömmlichen 2D-Elementen, die in einem räumlichen Container verpackt sind. Diese Elemente können in 2D- oder 3D-Layouts verwendet werden, wenn sie für beide definiert sind. Wenn die räumliche Darstellung nicht aktiviert ist, werden die räumlichen Elemente ignoriert und es wird auf die 2D-Entsprechungen zurückgegriffen.
Einen Bereich für die Raumerkennung erstellen
Ein SpatialPanel
ist ein zusammensetzbarer Unterraum, in dem Sie App-Inhalte anzeigen können. So können Sie beispielsweise Videowiedergabe, Standbilder oder andere Inhalte in einem Raumbereich anzeigen.
Mit SubspaceModifier
können Sie die Größe, das Verhalten und die Position des Bereichs „Statistiken für die Standortermittlung“ ändern, wie im folgenden Beispiel gezeigt.
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
)
}
}
Wichtige Punkte zum Code
- Da
SpatialPanel
APIs Subspace-Kompositionen sind, müssen sie inSubspace
odersetSubspaceContent
aufgerufen werden. Wenn Sie sie außerhalb eines Unterraums aufrufen, wird eine Ausnahme ausgelöst. - Sie können dem Nutzer erlauben, die Größe des Steuerfelds zu ändern oder es zu verschieben, indem Sie die Modifikatoren
movable
oderresizable
hinzufügen. - Weitere Informationen zu Größe und Positionierung finden Sie in unserer Anleitung zum Design von Infofeldern. Weitere Informationen zur Codeimplementierung finden Sie in unserer Referenzdokumentation.
Orbiter erstellen
Ein Orbiter ist eine räumliche UI-Komponente. Sie sind für die Verknüpfung mit einem entsprechenden Bereich, Layout oder einer anderen Entität vorgesehen. Ein Orbiter enthält in der Regel Navigations- und kontextbezogene Aktionselemente, die sich auf das angedockte Element beziehen. Wenn Sie beispielsweise ein räumliches Steuerfeld zum Anzeigen von Videoinhalten erstellt haben, können Sie die Steuerelemente für die Videowiedergabe in einem Orbiter hinzufügen.
Wie im folgenden Beispiel gezeigt, rufen Sie einen Orbiter innerhalb des 2D-Layouts in einer SpatialPanel
auf, um Nutzersteuerelemente wie die Navigation einzubinden. Dadurch werden sie aus Ihrem 2D-Layout extrahiert und gemäß Ihrer Konfiguration an das Infofeld für die Raumaufteilung angehängt.
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
)
}
}
}
}
Wichtige Punkte zum Code
- Da Orbiter räumliche UI-Komponenten sind, kann der Code in 2D- oder 3D-Layouts wiederverwendet werden. Bei einem 2D-Layout werden in Ihrer App nur die Inhalte innerhalb des Orbiters gerendert. Der Orbiter selbst wird ignoriert.
- Weitere Informationen zur Verwendung und Gestaltung von Orbitaren finden Sie in unseren Designrichtlinien.
Einem geografischen Layout mehrere Kartenbereiche hinzufügen
Mit SpatialRow
, SpatialColumn
, SpatialBox
und SpatialLayoutSpacer
können Sie mehrere Kartenkacheln erstellen und in einem Kartenlayout platzieren.
Im folgenden Codebeispiel wird gezeigt, wie Sie dies umsetzen.
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
)
}
}
Wichtige Punkte zum Code
SpatialRow
,SpatialColumn
,SpatialBox
undSpatialLayoutSpacer
sind alle Unterraum-Kompositen und müssen in einem Unterraum platziert werden.- Mit
SubspaceModifier
können Sie das Layout anpassen. - Für Layouts mit mehreren Bereichen in einer Zeile empfehlen wir, mithilfe eines
SubspaceModifier
einen Kurvenradius von 825 dp festzulegen, damit die Bereiche den Nutzer umgeben. Weitere Informationen finden Sie in unseren Designrichtlinien.
Mit einem Volume ein 3D‑Objekt in das Layout einfügen
Wenn Sie ein 3D‑Objekt in Ihr Layout einfügen möchten, müssen Sie ein zusammengesetztes Unterraumelement namens Volumen verwenden. Hier ein Beispiel dafür:
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
}
}
}
}
}
Wichtige Punkte zum Code
- Weitere Informationen zum Laden von 3D-Inhalten in einem Volume finden Sie unter 3D‑Modelle zu Ihrer App hinzufügen.
Andere UI-Komponenten für die Darstellung von Räumen hinzufügen
Räumliche UI-Komponenten können überall in der UI-Hierarchie Ihrer Anwendung platziert werden. Diese Elemente können in Ihrer 2D-Benutzeroberfläche wiederverwendet werden. Ihre räumlichen Attribute sind nur sichtbar, wenn die räumlichen Funktionen aktiviert sind. So können Sie Menüs, Dialogfelder und andere Komponenten hervorheben, ohne den Code zweimal schreiben zu müssen. Anhand der folgenden Beispiele für die räumliche Benutzeroberfläche können Sie besser nachvollziehen, wie Sie diese Elemente verwenden.
UI-Komponente |
Wenn die Spatialisierung aktiviert ist |
In einer 2D-Umgebung |
---|---|---|
|
Der Bereich wird in der Z-Tiefe leicht nach hinten verschoben, um ein erhöhtes Dialogfeld anzuzeigen. |
Kehrt zur 2D-Ansicht |
|
Der Bereich wird in der Z-Tiefe leicht nach hinten verschoben, um ein erhöhtes Pop-up anzuzeigen. |
Es wird zu einer 2D- |
|
Mit |
Darstellungen ohne räumliche Erhebungen. |
SpatialDialog
Das ist ein Beispiel für ein Dialogfeld, das nach einer kurzen Verzögerung geöffnet wird. Wenn SpatialDialog
verwendet wird, wird das Dialogfeld in derselben Z‑Tiefe wie das räumliche Steuerfeld angezeigt. Wenn die räumliche Darstellung aktiviert ist, wird das Steuerfeld um 125 dp nach hinten verschoben. SpatialDialog
kann auch verwendet werden, wenn die Spatialisierung nicht aktiviert ist. In diesem Fall greift SpatialDialog
auf sein 2D-Äquivalent Dialog
zurück.
@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")
}
}
}
}
}
Wichtige Punkte zum Code
- Dies ist ein Beispiel für
SpatialDialog
. Die Verwendung vonSpatialPopUp
undSpatialElevation
ist sehr ähnlich. Weitere Informationen finden Sie in der API-Referenz.
Benutzerdefinierte Bereiche und Layouts erstellen
Wenn Sie benutzerdefinierte Steuerfelder erstellen möchten, die von Compose for XR nicht unterstützt werden, können Sie mithilfe der SceneCore
APIs direkt mit PanelEntities
und der Szenengraphik arbeiten.
Orbiter an räumliche Layouts und andere Entitäten anpinnen
Sie können einen Orbiter an eine beliebige in Compose deklarierte Entität anpinnen. Dazu müssen Sie einen Orbiter in einem räumlichen Layout von UI-Elementen wie SpatialRow
, SpatialColumn
oder SpatialBox
deklarieren. Der Orbiter wird an der übergeordneten Entität verankert, die sich am nächsten an der Stelle befindet, an der Sie ihn deklariert haben.
Das Verhalten des Orbiters wird dadurch bestimmt, wo Sie ihn deklarieren:
- In einem 2D-Layout, das in einem
SpatialPanel
eingeschlossen ist (wie im vorangehenden Code-Snippet gezeigt), wird der Orbiter an diesemSpatialPanel
verankert. - In einer
Subspace
wird der Orbiter an der nächstgelegenen übergeordneten Entität verankert, also dem räumlichen Layout, in dem der Orbiter deklariert ist.
Im folgenden Beispiel wird gezeigt, wie ein Orbiter an einer geografischen Zeile verankert wird:
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)
)
}
}
}
Wichtige Punkte zum Code
- Wenn Sie einen Orbiter außerhalb eines 2D-Layouts deklarieren, wird er an der nächstgelegenen übergeordneten Entität verankert. In diesem Fall wird der Orbiter oben im
SpatialRow
verankert, in dem er deklariert ist. - Räumliche Layouts wie
SpatialRow
,SpatialColumn
undSpatialBox
sind alle mit entitätslosen Elementen verknüpft. Ein in einem räumlichen Layout deklarierter Orbiter wird daher an dieses Layout angedockt.
Siehe auch
- Ihrer App 3D‑Modelle hinzufügen
- Benutzeroberfläche für Android-Anwendungen mit Ansichten entwickeln
- Material Design für XR implementieren