Dzięki Jetpack Compose for XR możesz deklaratywnie tworzyć interfejs i układ przestrzenny, korzystając z dobrze znanych koncepcji Compose, takich jak wiersze i kolumny. Dzięki temu możesz rozszerzyć istniejące interfejs użytkownika Androida o przestrzeń 3D lub tworzyć zupełnie nowe, wciągające aplikacje 3D.
Jeśli chcesz dodać obsługę dźwięku przestrzennego w istniejącej aplikacji opartej na Android Views, masz do wyboru kilka opcji. Możesz używać interfejsów API interoperacyjności, używać komponentu Compose i widżetów razem lub pracować bezpośrednio z biblioteką SceneCore. Więcej informacji znajdziesz w przewodniku po widokach.
Informacje o podprzestrzeniach i komponentach przestrzennych
Podczas pisania aplikacji na Androida XR ważne jest zrozumienie koncepcji podprzestrzeni i przestrzennych komponentów.
Subspace
Podczas tworzenia aplikacji na Androida XR musisz dodać do niej podprzestrzeń lub układ. Subprzestrzeń to część przestrzeni 3D w aplikacji, w której możesz umieszczać treści 3D, tworzyć układy 3D i dodawać głębię do treści 2D. Subprzestrzeń jest renderowana tylko wtedy, gdy włączona jest przestrzenność. W domu lub na urządzeniach bez funkcji XR każdy kod w tym podprzestrzeni jest ignorowany.
Subprzestrzeń możesz utworzyć na 2 sposoby:
setSubspaceContent()
: ta funkcja tworzy podprzestrzeń na poziomie aplikacji. Możesz go wywołać w głównej aktywności w taki sam sposób, w jaki używaszsetContent()
. Subprzestrzeń na poziomie aplikacji jest nieograniczona pod względem wysokości, szerokości i głębi, co zapewnia nieskończoną przestrzeń dla treści przestrzennych.Subspace
: ten komponent może być umieszczony w dowolnym miejscu w hierarchii interfejsu aplikacji, co pozwala zachować układy interfejsu 2D i przestrzennego bez utraty kontekstu między plikami. Dzięki temu łatwiej jest udostępniać elementy, takie jak istniejąca architektura aplikacji, między XR a innymi formatami, bez konieczności przenoszenia stanu przez całe drzewo interfejsu użytkownika ani ponownego projektowania aplikacji.
Więcej informacji znajdziesz w artykule Dodawanie podprzestrzeni do aplikacji.
Komponenty zlokalizowane
Komponenty w podprzestrzeni: te komponenty można renderować tylko w podprzestrzeni.
Przed umieszczeniem w układzie 2D muszą być one umieszczone w elementach Subspace
lub setSubspaceContent
. SubspaceModifier
pozwala dodawać atrybuty, takie jak głębia, przesunięcie i pozycjonowanie, do komponentów w przestrzeni podrzędnej.
Inne komponenty przestrzenne nie wymagają wywołania w podprzestrzeni. Składają się one z tradycyjnych elementów 2D umieszczonych w kontenerze przestrzennym. Te elementy mogą być używane w układach 2D lub 3D, jeśli są zdefiniowane dla obu. Jeśli funkcja dźwięku przestrzennego jest wyłączona, funkcje dźwięku przestrzennego zostaną zignorowane, a dźwięk będzie odtwarzany w trybie 2D.
Tworzenie panelu dźwięku przestrzennego
SpatialPanel
to komponent podprzestrzeni, który umożliwia wyświetlanie treści aplikacji. Możesz na przykład wyświetlić film, obrazy statyczne lub inne treści w panelu przestrzennym.
Za pomocą SubspaceModifier
możesz zmienić rozmiar, zachowanie i pozycjonowanie panelu przestrzennego, jak pokazano w tym przykładzie.
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
)
}
}
Najważniejsze informacje o kodzie
- Interfejsy API
SpatialPanel
są elementami kompozytowymi w subprzestrzeni, więc musisz je wywoływać w ramachSubspace
lubsetSubspaceContent
. Wywoływanie ich poza subprzestrzenią powoduje wyjątek. - Umożliw użytkownikowi zmianę rozmiaru lub przeniesienie panelu, dodając modyfikatory
movable
lubresizable
. - Szczegółowe informacje o rozmiarach i umieszczaniu znajdziesz w wskazówkach dotyczących projektowania paneli przestrzennych. Więcej informacji o implementacji kodu znajdziesz w dokumentacji referencyjnej.
Tworzenie orbitera
Orbiter to komponent UI przestrzennego. Jest on przeznaczony do dołączenia do odpowiedniego panelu przestrzennego, układu lub innego elementu. Orbiter zwykle zawiera elementy nawigacji i działania kontekstowe związane z elementem, do którego jest zamocowany. Jeśli na przykład utworzysz panel przestrzenny, aby wyświetlać treści wideo, możesz dodać elementy sterujące odtwarzaniem filmu w orbicie.
Jak widać w tym przykładzie, wywołaj orbiter w ramach układu 2D w komponencie SpatialPanel
, aby owinąć elementy sterujące użytkownika, takie jak nawigacja. Spowoduje to wyodrębnienie obiektów z układu 2D i ich dołączenie do panelu przestrzennego zgodnie z konfiguracją.
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
)
}
}
}
}
Najważniejsze informacje o kodzie
- Orbitery to komponenty UI przestrzennego, więc kod można ponownie wykorzystać w układach 2D lub 3D. W układzie 2D aplikacja renderuje tylko zawartość wewnątrz orbitera i ignoruje sam orbiter.
- Więcej informacji o tym, jak używać i projektować orbitery, znajdziesz w wskazówkach dotyczących projektowania.
Dodawanie wielu paneli przestrzennych do układu przestrzennego
Możesz utworzyć wiele paneli przestrzennych i umieścić je w układzie przestrzennym, używając SpatialRow
, SpatialColumn
, SpatialBox
i SpatialLayoutSpacer
.
Jak to zrobić, pokazuje przykładowy kod poniżej.
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
)
}
}
Najważniejsze informacje o kodzie
SpatialRow
,SpatialColumn
,SpatialBox
iSpatialLayoutSpacer
to wszystkie komponenty podprzestrzeni, które muszą być umieszczone w podprzestrzeni.- Aby dostosować układ, użyj
SubspaceModifier
. - W przypadku układów z wieloma panelami w rzędzie zalecamy ustawienie krzywizny o promieniu 825 dp za pomocą funkcji
SubspaceModifier
, aby panele otaczały użytkownika. Szczegółowe informacje znajdziesz w wskazówkach dotyczących projektowania.
Umieszczanie obiektu 3D w układzie za pomocą wolumenu
Aby umieścić obiekt 3D w układzie, musisz użyć komponentu podprzestrzeni zwanego objętością. Oto przykład, jak to zrobić.
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
}
}
}
}
}
Najważniejsze informacje o kodzie
- Aby dowiedzieć się więcej o wczytywaniu treści 3D w ramach woluminu, przeczytaj artykuł Dodawanie modeli 3D do aplikacji.
Dodawanie innych komponentów UI w przestrzeni
Komponenty UI przestrzennego można umieścić w dowolnym miejscu w hierarchii UI aplikacji. Elementy te można ponownie wykorzystać w interfejsie 2D, a ich atrybuty przestrzenne będą widoczne tylko wtedy, gdy włączone są funkcje przestrzenne. Dzięki temu możesz dodawać menu, dialogi i inne komponenty bez konieczności dwukrotnego pisania kodu. Aby lepiej zrozumieć, jak używać tych elementów, zapoznaj się z podanymi niżej przykładami interfejsu przestrzennego.
Komponent interfejsu użytkownika |
Gdy włączona jest lokalizacja przestrzenna |
W środowisku 2D |
---|---|---|
|
Panel przesunie się nieco w głębi, aby wyświetlić okno dialogowe |
Przełącza się na widok 2D |
|
Panel przesunie się nieco w głębi, aby wyświetlić wyskakujące okienko |
Przełącza się na widok 2D |
|
|
programy bez dźwięku przestrzennego; |
SpatialDialog
Oto przykład okna, które otwiera się po krótkim opóźnieniu. Gdy używasz SpatialDialog
, okno pojawia się na tej samej głębi, co panel przestrzenny, a panel jest przesuwany do tyłu o 125 dp, gdy włączona jest lokalizacja przestrzenna. SpatialDialog
można też używać, gdy przestrzenność nie jest włączona. W takim przypadku SpatialDialog
przechodzi do swojego odpowiednika 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")
}
}
}
}
}
Najważniejsze informacje o kodzie
- Oto przykład
SpatialDialog
. UżycieSpatialPopUp
iSpatialElevation
jest bardzo podobne. Więcej informacji znajdziesz w dokumentacji interfejsu API.
Tworzenie paneli i układów niestandardowych
Aby tworzyć panele niestandardowe, których nie obsługuje Compose for XR, możesz pracować bezpośrednio z PanelEntities
i grafami sceny za pomocą interfejsów API SceneCore
.
stosowanie orbiterów do osi czasu i innych elementów,
Możesz zaankować orbiter do dowolnego elementu zadeklarowanego w składni. Polega to na zadeklarowaniu orbitera w układzie przestrzennym elementów interfejsu, takich jak SpatialRow
, SpatialColumn
lub SpatialBox
. Orbiter jest przytwierdzony do nadrzędnego elementu, który znajduje się najbliżej miejsca jego zadeklarowania.
Zachowanie orbitera zależy od miejsca jego zadeklarowania:
- W układzie 2D ujętym w element
SpatialPanel
(jak pokazano w poprzednim fragmentie kodu), orbiter jest zakotwiczony w tym elemencieSpatialPanel
. - W
Subspace
orbiter jest zakotwiczony do najbliższej nadrzędnej, czyli do układu przestrzennego, w którym jest zadeklarowany.
Ten przykład pokazuje, jak zakotwiczyć orbiter w wierszu przestrzennym:
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)
)
}
}
}
Najważniejsze informacje o kodzie
- Jeśli deklarujesz orbiter poza układem 2D, orbiter jest przytwierdzony do najbliższego elementu nadrzędnego. W tym przypadku orbiter jest zakotwiczony u góry deklarowanej przez siebie kolumny
SpatialRow
. - Układy przestrzenne, takie jak
SpatialRow
,SpatialColumn
iSpatialBox
, mają powiązane z sobą elementy bez treści. Dlatego orbiter zadeklarowany w układzie przestrzennym jest do niego przywiązany.
Zobacz również
- Dodawanie modeli 3D do aplikacji
- Tworzenie interfejsu użytkownika dla aplikacji opartych na widokach Androida
- Zastosowanie Material Design w przypadku XR