Mengembangkan UI dengan Jetpack Compose untuk XR

Dengan Jetpack Compose untuk XR, Anda dapat mem-build UI dan tata letak spasial secara deklaratif menggunakan konsep Compose yang sudah dikenal seperti baris dan kolom. Hal ini memungkinkan Anda memperluas UI Android yang ada ke ruang 3D atau membuat aplikasi 3D imersif yang benar-benar baru.

Jika Anda melakukan spatialisasi pada aplikasi berbasis View Android yang ada, Anda memiliki beberapa opsi pengembangan. Anda dapat menggunakan API interoperabilitas, menggunakan Compose dan View secara bersamaan, atau bekerja langsung dengan library SceneCore. Lihat panduan untuk menggunakan tampilan kami untuk mengetahui detail selengkapnya.

Tentang subspace dan komponen yang di-spatialisasi

Saat menulis aplikasi untuk Android XR, penting untuk memahami konsep subruang dan komponen spasial.

Tentang subspace

Saat mengembangkan untuk Android XR, Anda harus menambahkan subspace ke aplikasi atau tata letak. Subruang adalah partisi ruang 3D dalam aplikasi tempat Anda dapat menempatkan konten 3D, membuat tata letak 3D, dan menambahkan kedalaman ke konten 2D. Subruang hanya dirender jika spatialisasi diaktifkan. Di Ruang Rumah atau di perangkat non-XR, kode apa pun dalam subruang tersebut akan diabaikan.

Ada dua cara untuk membuat subruang:

  • setSubspaceContent: Fungsi ini membuat subruang tingkat aplikasi. Ini dapat dipanggil di MainActivity dengan cara yang sama seperti Anda menggunakan setContent. Subruang tingkat aplikasi tidak terbatas dalam tinggi, lebar, dan kedalaman, yang pada dasarnya menyediakan kanvas tanpa batas untuk konten spasial.
  • Subspace: Composable ini dapat ditempatkan di mana saja dalam hierarki UI aplikasi, sehingga Anda dapat mempertahankan tata letak untuk UI 2D dan spasial tanpa kehilangan konteks antar-file. Hal ini memudahkan Anda untuk berbagi hal-hal seperti arsitektur aplikasi yang ada antara XR dan faktor bentuk lainnya tanpa perlu mengangkat status melalui seluruh hierarki UI atau mendesain ulang aplikasi.

Untuk informasi selengkapnya, baca artikel tentang menambahkan subspace ke aplikasi.

Tentang komponen spasial

Composable subspace: Komponen ini hanya dapat dirender di subspace. Elemen ini harus diapit dalam Subspace atau setSubspaceContent sebelum ditempatkan dalam tata letak 2D. SubspaceModifier memungkinkan Anda menambahkan atribut seperti kedalaman, offset, dan pemosisian ke composable subspace.

  • Catatan tentang pengubah subspace: Perhatikan dengan cermat urutan SubspaceModifier API.
    • Offset harus terjadi terlebih dahulu dalam rantai pengubah
    • Dapat dipindahkan dan diubah ukurannya harus terjadi terakhir
    • Rotasi harus diterapkan sebelum penskalaan

Komponen spasial lainnya tidak perlu dipanggil di dalam subruang. Elemen ini terdiri dari elemen 2D konvensional yang digabungkan dalam penampung spasial. Elemen ini dapat digunakan dalam tata letak 2D atau 3D jika ditentukan untuk keduanya. Jika pemosisian spasial tidak diaktifkan, fitur yang diposisikan secara spasial akan diabaikan dan akan kembali ke versi 2D-nya.

Membuat panel spasial

SpatialPanel adalah composable subspace yang memungkinkan Anda menampilkan konten aplikasi. Misalnya, Anda dapat menampilkan pemutaran video, gambar diam, atau konten lainnya di panel spasial.

Contoh panel UI spasial

Anda dapat menggunakan SubspaceModifier untuk mengubah ukuran, perilaku, dan pemosisian panel spasial, seperti yang ditunjukkan dalam contoh berikut.

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

Poin penting tentang kode

  • Catatan tentang pengubah subspace: Perhatikan dengan cermat urutan SubspaceModifier API.
    • Offset harus terjadi terlebih dahulu dalam rantai pengubah.
    • Pengubah yang dapat dipindahkan dan diubah ukurannya harus terjadi terakhir.
    • Rotasi harus diterapkan sebelum skala.
  • Karena SpatialPanel API adalah composable subspace, Anda harus memanggilnya di dalam Subspace atau setSubspaceContent. Memanggilnya di luar subruang akan menampilkan pengecualian.
  • Izinkan pengguna mengubah ukuran atau memindahkan panel dengan menambahkan .movable atau .resizable SubspaceModifier.
  • Lihat panduan desain panel spasial kami untuk mengetahui detail tentang ukuran dan pemosisi. Lihat dokumentasi referensi kami untuk mengetahui detail selengkapnya tentang penerapan kode.

Membuat orbiter

Orbiter adalah komponen UI spasial. Panel ini dirancang untuk dilampirkan ke panel spasial yang sesuai, dan berisi navigasi serta item tindakan kontekstual yang terkait dengan panel spasial tersebut. Misalnya, jika telah membuat panel spasial untuk menampilkan konten video, Anda dapat menambahkan kontrol pemutaran video di dalam orbiter.

Contoh orbiter

Seperti yang ditunjukkan dalam contoh berikut, panggil orbiter di dalam SpatialPanel untuk menggabungkan kontrol pengguna seperti navigasi. Tindakan ini akan mengekstraknya dari tata letak 2D dan melampirkan ke panel spasial sesuai dengan konfigurasi Anda.

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

Poin penting tentang kode

  • Catatan tentang Pengubah Subruang: Perhatikan dengan cermat urutan SubspaceModifier API.
    • Offset harus terjadi terlebih dahulu dalam rantai pengubah
    • Dapat dipindahkan dan diubah ukurannya harus terjadi terakhir
    • Rotasi harus diterapkan sebelum penskalaan
  • Karena orbiter adalah komponen UI spasial, kode dapat digunakan kembali dalam tata letak 2D atau 3D. Dalam tata letak 2D, aplikasi Anda hanya merender konten di dalam orbiter dan mengabaikan orbiter itu sendiri.
  • Lihat panduan desain kami untuk informasi selengkapnya tentang cara menggunakan dan mendesain orbiter.

Menambahkan beberapa panel spasial ke tata letak spasial

Anda dapat membuat beberapa panel spasial dan menempatkannya dalam tata letak spasial menggunakan SpatialRow, SpatialColumn, SpatialBox, dan SpatialLayoutSpacer.

Contoh beberapa panel spasial dalam tata letak spasial

Contoh kode berikut menunjukkan cara melakukannya.

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

Poin penting tentang kode

  • SpatialRow, SpatialColumn, SpatialBox, dan SpatialLayoutSpacer adalah composable subspace dan harus ditempatkan dalam subspace.
  • Gunakan SubspaceModifier untuk menyesuaikan tata letak.
  • Untuk tata letak dengan beberapa panel dalam satu baris, sebaiknya tetapkan radius kurva 825dp menggunakan SubspaceModifier sehingga panel akan mengelilingi pengguna Anda. Lihat panduan desain kami untuk mengetahui detailnya.

Menggunakan volume untuk menempatkan objek 3D dalam tata letak

Untuk menempatkan objek 3D dalam tata letak, Anda harus menggunakan composable subspace yang disebut volume. Berikut adalah contoh cara melakukannya.

Contoh objek 3D dalam tata letak

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

Poin penting tentang kode

  • Catatan tentang Pengubah Subruang: Perhatikan dengan cermat urutan SubspaceModifier API.
    • Offset harus terjadi terlebih dahulu dalam rantai pengubah
    • Dapat dipindahkan dan diubah ukurannya harus terjadi terakhir
    • Rotasi harus diterapkan sebelum penskalaan
  • Lihat Menambahkan konten 3D untuk lebih memahami cara memuat konten 3D dalam volume.

Menambahkan komponen UI spasial lainnya

Komponen UI spasial dapat ditempatkan di mana saja dalam hierarki UI aplikasi Anda. Elemen ini dapat digunakan kembali di UI 2D Anda, dan atribut spasialnya hanya akan terlihat saat kemampuan spasial diaktifkan. Hal ini memungkinkan Anda menambahkan elevasi ke menu, dialog, dan komponen lainnya tanpa perlu menulis kode dua kali. Lihat contoh UI spasial berikut untuk lebih memahami cara menggunakan elemen ini.

Komponen UI

Saat spasialisasi diaktifkan

Di lingkungan 2D

SpatialDialog

Panel akan sedikit mendorong kedalaman z untuk menampilkan dialog yang ditinggikan

Melakukan fallback ke 2D Dialog.

SpatialPopUp

Panel akan sedikit didorong kembali dalam kedalaman z untuk menampilkan pop-up yang ditinggikan

Melakukan fallback ke PopUp 2D.

SpatialElevation

SpatialElevationLevel dapat disetel untuk menambahkan elevasi.

Menampilkan tanpa elevasi spasial.

SpatialDialog

Ini adalah contoh dialog yang terbuka setelah penundaan singkat. Saat SpatialDialog digunakan, dialog akan muncul pada kedalaman z yang sama dengan panel spasial, dan panel akan didorong kembali sebesar 125dp saat spasialisasi diaktifkan. SpatialDialog masih dapat digunakan jika spatialisasi juga tidak diaktifkan, dan akan kembali ke versi 2D-nya: 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")
               }
           }
       }
   }
}

Poin penting tentang kode

Membuat panel dan tata letak kustom

Untuk membuat panel kustom yang tidak didukung oleh Compose untuk XR, Anda dapat bekerja langsung dengan PanelEntities dan grafik tampilan menggunakan SceneCore API.

Lihat juga