เมื่อใช้ Jetpack Compose สำหรับ XR คุณจะสร้าง UI และเลย์เอาต์เชิงพื้นที่แบบประกาศได้โดยใช้แนวคิด Compose ที่คุ้นเคย เช่น แถวและคอลัมน์ ซึ่งจะช่วยให้คุณขยาย UI ของ Android ที่มีอยู่ไปยังพื้นที่ 3 มิติ หรือสร้างแอปพลิเคชัน 3 มิติที่สมจริงแบบใหม่ทั้งหมด
หากกำลังทำให้แอปที่มีอยู่ซึ่งอิงตาม Android Views เป็นโมเดลเชิงพื้นที่ คุณจะมีตัวเลือกการพัฒนาหลายอย่าง คุณสามารถใช้ API การทํางานร่วมกัน ใช้ Compose และ Views ร่วมกัน หรือทํางานกับไลบรารี SceneCore โดยตรงก็ได้ ดูรายละเอียดเพิ่มเติมได้ในคำแนะนำเกี่ยวกับวิธีทำงานกับมุมมอง
เกี่ยวกับพื้นที่ย่อยและคอมโพเนนต์ที่แยกแยะเสียงตามตำแหน่ง
เมื่อเขียนแอปสำหรับ Android XR คุณควรทำความเข้าใจแนวคิดของพื้นที่ย่อยและคอมโพเนนต์ที่ปรับเปลี่ยนตามพื้นที่
เกี่ยวกับพาร์ทเนอร์ย่อย
เมื่อพัฒนาแอปสำหรับ Android XR คุณจะต้องเพิ่มพื้นที่ย่อยลงในแอปหรือเลย์เอาต์ พื้นที่ย่อยคือการแบ่งพื้นที่ 3 มิติภายในแอป ซึ่งคุณสามารถวางเนื้อหา 3 มิติ สร้างเลย์เอาต์ 3 มิติ และเพิ่มมิติให้กับเนื้อหา 2 มิติ ระบบจะแสดงผลพื้นที่ย่อยก็ต่อเมื่อเปิดใช้การจัดวางเสียงเท่านั้น ใน Home Space หรือในอุปกรณ์ที่ไม่ใช่ XR ระบบจะไม่สนใจโค้ดภายในพื้นที่ย่อยนั้น
การสร้างพื้นที่ทำงานย่อยทำได้ 2 วิธีดังนี้
setSubspaceContent
: ฟังก์ชันนี้จะสร้างพื้นที่ทำงานย่อยระดับแอป ซึ่งเรียกได้ใน MainActivity เช่นเดียวกับที่ใช้setContent
พื้นที่ทำงานย่อยระดับแอปมีความสูง กว้าง และลึกได้ไม่จำกัด ซึ่งโดยพื้นฐานแล้วจะเป็นผืนผ้าใบที่ไม่มีที่สิ้นสุดสำหรับเนื้อหาเชิงพื้นที่Subspace
: คอมโพสิชันนี้สามารถวางไว้ที่ใดก็ได้ภายในลําดับชั้น UI ของแอป ซึ่งช่วยให้คุณคงเลย์เอาต์สําหรับ UI 2 มิติและ UI เชิงพื้นที่ไว้ได้โดยไม่สูญเสียบริบทระหว่างไฟล์ วิธีนี้ช่วยให้แชร์สิ่งต่างๆ เช่น สถาปัตยกรรมแอปที่มีอยู่ระหว่าง XR กับอุปกรณ์รูปแบบอื่นๆ ได้ง่ายขึ้นโดยไม่ต้องยกสถานะผ่านทั้งต้นไม้ UI หรือปรับโครงสร้างแอปใหม่
ดูข้อมูลเพิ่มเติมได้ที่การเพิ่มพื้นที่ทำงานย่อยลงในแอป
เกี่ยวกับคอมโพเนนต์ที่วางตำแหน่งตามพื้นที่
คอมโพเนนต์ที่คอมโพสิเบิลในซับสเปซ: คอมโพเนนต์เหล่านี้จะแสดงผลได้ในซับสเปซเท่านั้น
โดยต้องใส่ไว้ใน Subspace
หรือ setSubspaceContent
ก่อนวางไว้ในเลย์เอาต์ 2 มิติ SubspaceModifier
ช่วยให้คุณเพิ่มแอตทริบิวต์ต่างๆ เช่น ระดับความลึก การเลื่อน และการวางตำแหน่ง ลงในคอมโพสิชันย่อยได้
- หมายเหตุเกี่ยวกับตัวแก้ไขพื้นที่ย่อย: โปรดตรวจสอบลำดับของ
SubspaceModifier
API อย่างละเอียด- ออฟเซ็ตต้องอยู่ก่อนสุดในเชนตัวแก้ไข
- ย้ายได้และปรับขนาดได้ต้องแสดงเป็นค่าสุดท้าย
- ต้องใช้การหมุนก่อนการปรับขนาด
คอมโพเนนต์อื่นๆ ที่ปรับเปลี่ยนให้เข้ากับพื้นที่ไม่จำเป็นต้องเรียกใช้ภายในซับสเปซ โดยประกอบด้วยองค์ประกอบ 2 มิติแบบดั้งเดิมที่รวมอยู่ในคอนเทนเนอร์เชิงพื้นที่ องค์ประกอบเหล่านี้ใช้ได้ภายในเลย์เอาต์ 2 มิติหรือ 3 มิติ หากกำหนดไว้สำหรับทั้ง 2 รูปแบบ เมื่อไม่ได้เปิดใช้การจัดวางเชิงพื้นที่ ระบบจะไม่สนใจฟีเจอร์ที่จัดวางเชิงพื้นที่และฟีเจอร์ดังกล่าวจะเปลี่ยนกลับไปเป็นฟีเจอร์ 2 มิติ
สร้างแผงเชิงพื้นที่
SpatialPanel
คือคอมโพสิชันย่อยที่ให้คุณแสดงเนื้อหาแอปได้ เช่น คุณสามารถแสดงการเล่นวิดีโอ ภาพนิ่ง หรือเนื้อหาอื่นๆ ในแผงพื้นที่ทำงาน
คุณสามารถใช้ SubspaceModifier
เพื่อเปลี่ยนขนาด ลักษณะการทำงาน และตำแหน่งของแผงเชิงพื้นที่ได้ ดังที่แสดงในตัวอย่างต่อไปนี้
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
)
}
}
ประเด็นสำคัญเกี่ยวกับรหัส
- หมายเหตุเกี่ยวกับตัวแก้ไขพื้นที่ย่อย: โปรดตรวจสอบลำดับของ API
SubspaceModifier
อย่างละเอียด- ออฟเซตต้องปรากฏขึ้นก่อนในเชนตัวแก้ไข
- โมดิฟายเออร์ที่ย้ายได้และปรับขนาดได้ต้องอยู่ท้ายสุด
- ต้องหมุนก่อนปรับขนาด
- เนื่องจาก API ของ
SpatialPanel
เป็นแบบคอมโพสิเบิลของซับสเปซ คุณต้องเรียกใช้ API เหล่านั้นภายในSubspace
หรือsetSubspaceContent
การเรียกใช้นอกอวกาศย่อยจะทำให้เกิดข้อยกเว้น - อนุญาตให้ผู้ใช้ปรับขนาดหรือย้ายแผงโดยเพิ่ม
.movable
หรือ.resizable
SubspaceModifier
- ดูรายละเอียดเกี่ยวกับขนาดและตำแหน่งได้ในคำแนะนำการออกแบบแผงพื้นที่ทำงาน ดูรายละเอียดเพิ่มเติมเกี่ยวกับการติดตั้งโค้ดได้ในเอกสารอ้างอิง
สร้างดาวเทียมโคจร
วงโคจรคือคอมโพเนนต์ UI เชิงพื้นที่ ออกแบบมาเพื่อแนบกับแผงเชิงพื้นที่ที่เกี่ยวข้อง และมีรายการการนำทางและรายการการดำเนินการตามบริบทที่เกี่ยวข้องกับแผงเชิงพื้นที่นั้น เช่น หากสร้างแผงเชิงพื้นที่เพื่อแสดงเนื้อหาวิดีโอ คุณสามารถเพิ่มตัวควบคุมการเล่นวิดีโอไว้ในยานอวกาศ
ดังที่แสดงในตัวอย่างต่อไปนี้ ให้เรียกใช้ออบบิทภายใน SpatialPanel
เพื่อรวมการควบคุมของผู้ใช้ เช่น การนําทาง ซึ่งจะดึงข้อมูลออกจากเลย์เอาต์ 2 มิติ และแนบกับแผงเชิงพื้นที่ตามการกำหนดค่าของคุณ
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
)
}
}
}
}
ประเด็นสำคัญเกี่ยวกับรหัส
- หมายเหตุเกี่ยวกับตัวแก้ไขพื้นที่ย่อย: โปรดตรวจสอบลำดับของ
SubspaceModifier
API อย่างละเอียด- ออฟเซ็ตต้องอยู่ก่อนสุดในเชนตัวแก้ไข
- ย้ายได้และปรับขนาดได้ต้องแสดงเป็นค่าสุดท้าย
- ต้องใช้การหมุนก่อนการปรับขนาด
- เนื่องจาก Orbiter เป็นคอมโพเนนต์ UI เชิงพื้นที่ คุณจึงนำโค้ดไปใช้ซ้ำในเลย์เอาต์ 2 มิติหรือ 3 มิติได้ ในเลย์เอาต์ 2 มิติ แอปจะแสดงผลเฉพาะเนื้อหาภายในวงโคจร และจะไม่สนใจวงโคจรเอง
- ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้และออกแบบดาวเทียมโคจรได้ในคำแนะนำด้านการออกแบบ
เพิ่มแผงพื้นที่หลายรายการลงในเลย์เอาต์พื้นที่
คุณสามารถสร้างแผงพื้นที่หลายแผงแล้ววางไว้ในเลย์เอาต์พื้นที่ได้โดยใช้ SpatialRow
,
SpatialColumn
, SpatialBox
และ
SpatialLayoutSpacer
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีดำเนินการ
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
)
}
}
ประเด็นสำคัญเกี่ยวกับรหัส
SpatialRow
,SpatialColumn
,SpatialBox
และSpatialLayoutSpacer
ทั้งหมดเป็นคอมโพสิชันย่อยและต้องวางไว้ภายในซับสเปซ- ใช้
SubspaceModifier
เพื่อปรับแต่งเลย์เอาต์ - สำหรับเลย์เอาต์ที่มีแผงหลายแผงในแถวเดียว เราขอแนะนำให้กำหนดรัศมีของเส้นโค้งเป็น 825dp โดยใช้
SubspaceModifier
เพื่อให้แผงล้อมรอบผู้ใช้ ดูรายละเอียดได้ในคำแนะนำด้านการออกแบบ
ใช้ปริมาตรเพื่อวางวัตถุ 3 มิติในเลย์เอาต์
หากต้องการวางวัตถุ 3 มิติในเลย์เอาต์ คุณจะต้องคอมโพสิชันย่อยที่เรียกว่าปริมาตร ต่อไปนี้เป็นตัวอย่างวิธีดำเนินการ
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
}
}
}
}
}
ประเด็นสำคัญเกี่ยวกับรหัส
- หมายเหตุเกี่ยวกับตัวแก้ไขพื้นที่ย่อย: โปรดตรวจสอบลำดับของ
SubspaceModifier
API อย่างละเอียด- ออฟเซ็ตต้องอยู่ก่อนสุดในเชนตัวแก้ไข
- ย้ายได้และปรับขนาดได้ต้องแสดงเป็นค่าสุดท้าย
- ต้องใช้การหมุนก่อนการปรับขนาด
- ดูการเพิ่มเนื้อหา 3 มิติเพื่อให้เข้าใจวิธีโหลดเนื้อหา 3 มิติภายในโวลุ่มได้ดียิ่งขึ้น
เพิ่มคอมโพเนนต์ UI เชิงพื้นที่อื่นๆ
คอมโพเนนต์ UI เชิงพื้นที่สามารถวางไว้ที่ใดก็ได้ในลําดับชั้น UI ของแอปพลิเคชัน คุณนําองค์ประกอบเหล่านี้มาใช้ซ้ำใน UI 2 มิติได้ และแอตทริบิวต์เชิงพื้นที่จะปรากฏขึ้นก็ต่อเมื่อเปิดใช้ความสามารถเชิงพื้นที่เท่านั้น ซึ่งช่วยให้คุณเพิ่มระดับให้กับเมนู กล่องโต้ตอบ และคอมโพเนนต์อื่นๆ ได้โดยไม่ต้องเขียนโค้ดซ้ำ ดูตัวอย่าง UI เชิงพื้นที่ต่อไปนี้เพื่อให้เข้าใจวิธีใช้องค์ประกอบเหล่านี้ได้ดียิ่งขึ้น
คอมโพเนนต์ UI |
เมื่อเปิดใช้การจัดวางเสียงตามตำแหน่ง |
ในสภาพแวดล้อม 2 มิติ |
---|---|---|
|
แผงจะดันกลับเล็กน้อยใน Z-depth เพื่อแสดงกล่องโต้ตอบที่ยกระดับ |
กลับไปเป็น 2 มิติ |
|
แผงจะดันกลับเล็กน้อยใน Z-depth เพื่อแสดงป๊อปอัปที่ยกสูงขึ้น |
เปลี่ยนกลับไปเป็น 2 มิติ |
|
|
รายการที่ไม่มีการยกระดับเชิงพื้นที่ |
SpatialDialog
นี่เป็นตัวอย่างของกล่องโต้ตอบที่เปิดขึ้นหลังจากรอสักครู่ เมื่อใช้ SpatialDialog
กล่องโต้ตอบจะปรากฏที่ระดับความลึก z เดียวกับแผงเชิงพื้นที่ และระบบจะดันแผงกลับ 125dp เมื่อเปิดใช้การจัดวางเชิงพื้นที่
SpatialDialog
จะยังคงใช้งานได้เมื่อไม่ได้เปิดใช้การจัดวางเชิงพื้นที่ด้วย และระบบจะเปลี่ยนไปใช้ Dialog
ซึ่งเป็นรูปแบบ 2 มิติ
@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")
}
}
}
}
}
ประเด็นสำคัญเกี่ยวกับรหัส
- ตัวอย่างของ
SpatialDialog
การใช้SpatialPopUp
และSpatialElevation
จะคล้ายกันมาก ดูรายละเอียดเพิ่มเติมได้ที่ข้อมูลอ้างอิง API
สร้างแผงและเลย์เอาต์ที่กําหนดเอง
หากต้องการสร้างแผงที่กำหนดเองซึ่ง Compose for XR ไม่รองรับ คุณสามารถทำงานกับ PanelEntities
และกราฟฉากได้โดยตรงโดยใช้ SceneCore
API