توسعه رابط کاربری با Jetpack Compose برای XR

با Jetpack Compose برای XR، می‌توانید رابط کاربری و طرح‌بندی فضایی خود را با استفاده از مفاهیم آشنای Compose مانند سطرها و ستون‌ها به‌طور آشکار بسازید. این به شما امکان می دهد رابط کاربری اندروید موجود خود را به فضای سه بعدی گسترش دهید یا برنامه های سه بعدی همهجانبه کاملاً جدیدی بسازید.

اگر یک برنامه موجود مبتنی بر Views اندروید را فضایی می کنید، چندین گزینه توسعه دارید. می‌توانید از APIهای قابلیت همکاری استفاده کنید، از Compose و Views با هم استفاده کنید یا مستقیماً با کتابخانه SceneCore کار کنید. برای جزئیات بیشتر به راهنمای ما برای کار با نماها مراجعه کنید.

درباره فضاهای فرعی و اجزای فضایی

هنگامی که برنامه خود را برای Android XR می نویسید، درک مفاهیم زیرفضا و اجزای فضایی بسیار مهم است.

درباره زیرفضا

هنگام توسعه برای Android XR، باید یک فضای فرعی به برنامه یا طرح‌بندی خود اضافه کنید. فضای فرعی پارتیشنی از فضای سه بعدی در برنامه شما است که می توانید محتوای سه بعدی را قرار دهید، طرح بندی های سه بعدی بسازید و به محتوای دو بعدی در غیر این صورت عمق دهید. یک فضای فرعی تنها زمانی ارائه می شود که فضایی سازی فعال باشد. در Home Space یا در دستگاه‌های غیر XR، هر کدی در آن زیرفضا نادیده گرفته می‌شود.

دو راه برای ایجاد زیرفضا وجود دارد:

  • setSubspaceContent() : این تابع یک فضای فرعی در سطح برنامه ایجاد می کند. این را می توان در اکتیویتی اصلی شما به همان روشی که از setContent() استفاده می کنید فراخوانی کرد. یک زیرفضای سطح برنامه از نظر ارتفاع، عرض و عمق نامحدود است و اساساً یک بوم بی‌نهایت برای محتوای فضایی فراهم می‌کند.
  • Subspace : این قابل ترکیب را می توان در هر جایی در سلسله مراتب UI برنامه شما قرار داد، به شما این امکان را می دهد که طرح بندی ها را برای UI دو بعدی و فضایی بدون از دست دادن زمینه بین فایل ها حفظ کنید. این کار اشتراک‌گذاری مواردی مانند معماری برنامه‌های موجود بین XR و سایر فاکتورهای شکل را بدون نیاز به بالا بردن حالت در کل درخت رابط کاربری یا معماری مجدد برنامه‌تان آسان‌تر می‌کند.

برای اطلاعات بیشتر، به افزودن یک فضای فرعی به برنامه خود مراجعه کنید.

درباره اجزای فضایی

زیرفضاهای composable : این مولفه‌ها فقط در یک زیرفضا قابل ارائه هستند. آنها باید قبل از قرار گرفتن در یک طرح دو بعدی در Subspace یا setSubspaceContent محصور شوند. یک SubspaceModifier به شما امکان می‌دهد ویژگی‌هایی مانند عمق، افست و موقعیت‌یابی را به زیرفضای composable خود اضافه کنید.

سایر اجزای فضایی نیازی به فراخوانی در یک زیرفضا ندارند. آنها از عناصر دو بعدی معمولی تشکیل شده اند که در یک ظرف فضایی پیچیده شده اند. اگر برای هر دو تعریف شده باشد، می توان از این عناصر در طرح بندی های دو بعدی یا سه بعدی استفاده کرد. وقتی فضایی‌سازی فعال نباشد، ویژگی‌های فضایی آن‌ها نادیده گرفته می‌شود و به همتایان دوبعدی خود بازمی‌گردند.

یک پانل فضایی ایجاد کنید

SpatialPanel یک فضای فرعی قابل ترکیب است که به شما امکان می دهد محتوای برنامه را نمایش دهید – برای مثال، می توانید پخش ویدیو، تصاویر ثابت یا هر محتوای دیگری را در یک پانل فضایی نمایش دهید.

نمونه ای از پانل UI فضایی

همانطور که در مثال زیر نشان داده شده است می توانید از 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
        )
    }
}

نکات کلیدی در مورد کد

  • از آنجایی که SpatialPanel APIهای زیرفضایی قابل ترکیب هستند، باید آنها را در Subspace یا setSubspaceContent فراخوانی کنید. فراخوانی آنها در خارج از یک زیرفضا یک استثنا ایجاد می کند.
  • به کاربر امکان تغییر اندازه یا جابجایی پانل را با افزودن اصلاح‌کننده‌های movable یا resizable اندازه بدهید.
  • برای جزئیات در مورد اندازه و موقعیت به راهنمای طراحی پانل فضایی ما مراجعه کنید. برای جزئیات بیشتر در مورد اجرای کد به مستندات مرجع ما مراجعه کنید.

یک مدارگرد ایجاد کنید

مدارگرد یک جزء رابط کاربری فضایی است. این طراحی شده است تا به یک پانل فضایی، چیدمان یا موجودیت دیگر متصل شود. یک مدارگرد معمولاً شامل موارد ناوبری و کنش متنی مربوط به نهادی است که روی آن لنگر انداخته است. برای مثال، اگر یک پانل فضایی برای نمایش محتوای ویدیویی ایجاد کرده‌اید، می‌توانید کنترل‌های پخش ویدیو را در یک مدارگرد اضافه کنید.

نمونه ای از مدارگرد

همانطور که در مثال زیر نشان داده شده است، یک مدارگرد را در داخل طرح دو بعدی در SpatialPanel فراخوانی کنید تا کنترل‌های کاربر مانند ناوبری را بپیچید. با انجام این کار آنها را از چیدمان دوبعدی شما استخراج کرده و با توجه به پیکربندی شما به پانل فضایی متصل می کند.

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

نکات کلیدی در مورد کد

  • از آنجا که مدارگردها اجزای رابط کاربری فضایی هستند، کد را می توان در طرح‌بندی‌های دو بعدی یا سه بعدی استفاده کرد. در یک طرح دو بعدی، برنامه شما فقط محتوای داخل مدارگرد را رندر می کند و خود مدارگرد را نادیده می گیرد.
  • برای اطلاعات بیشتر در مورد نحوه استفاده و طراحی مدارگردها، راهنمای طراحی ما را بررسی کنید.

چند پانل فضایی را به یک طرح فضایی اضافه کنید

با استفاده از 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 بعدی در طرح خود استفاده کنید

برای قرار دادن یک شی سه بعدی در چیدمان خود، باید از یک فضای فرعی به نام حجم استفاده کنید. در اینجا مثالی از نحوه انجام این کار آورده شده است.

نمونه ای از یک شی سه بعدی در یک طرح

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

نکات کلیدی در مورد کد

سایر اجزای رابط کاربری فضایی را اضافه کنید

اجزای فضایی UI را می توان در هر نقطه از سلسله مراتب UI برنامه شما قرار داد. این عناصر را می‌توان در رابط کاربری دوبعدی شما استفاده مجدد کرد و ویژگی‌های فضایی آنها تنها زمانی قابل مشاهده خواهند بود که قابلیت‌های فضایی فعال باشند. این به شما امکان می دهد بدون نیاز به دوبار نوشتن کد خود، ارتفاع را به منوها، دیالوگ ها و سایر اجزاء اضافه کنید. برای درک بهتر نحوه استفاده از این عناصر، نمونه‌های زیر از رابط کاربری فضایی را ببینید.

کامپوننت UI

وقتی فضایی سازی فعال است

در محیط دو بعدی

SpatialDialog

پانل کمی به عقب در عمق z فشار می آورد تا یک گفتگوی بالا را نمایش دهد

به Dialog دوبعدی باز می گردد.

SpatialPopUp

پانل کمی به عقب در عمق z فشار می آورد تا یک پنجره بازشوی بالا نمایش داده شود

به یک PopUp دوبعدی برمی گردد.

SpatialElevation

SpatialElevationLevel می توان برای اضافه کردن ارتفاع تنظیم کرد.

نمایش بدون ارتفاع مکانی.

فضایی دیالوگ

این نمونه ای از گفتگو است که پس از یک تاخیر کوتاه باز می شود. هنگامی که از SpatialDialog استفاده می شود، گفتگو در همان عمق z مانند پانل فضایی ظاهر می شود، و پانل با 125dp به عقب رانده می شود زمانی که فضایی سازی فعال است. SpatialDialog همچنین می‌تواند زمانی استفاده شود که فضایی‌سازی فعال نباشد، در این صورت SpatialDialog به همتای دوبعدی خود، 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")
               }
           }
       }
   }
}

نکات کلیدی در مورد کد

پانل ها و طرح بندی های سفارشی ایجاد کنید

برای ایجاد پنل‌های سفارشی که توسط Compose برای XR پشتیبانی نمی‌شوند، می‌توانید مستقیماً با PanelEntities و نمودار صحنه با استفاده از APIهای SceneCore کار کنید.

مدارگردها را به طرح‌بندی‌های فضایی و موجودیت‌های دیگر لنگر می‌اندازد

می‌توانید مدارگرد را به هر موجودی که در Compose اعلام شده است متصل کنید. این شامل اعلان یک مدارگرد در یک طرح فضایی از عناصر UI مانند SpatialRow ، SpatialColumn یا SpatialBox است. مدارگرد به نزدیکترین موجودیت اصلی به جایی که شما آن را اعلام کرده اید متصل می شود.

رفتار مدارگرد توسط جایی که شما آن را اعلام می کنید تعیین می شود:

  • در یک طرح دوبعدی پیچیده شده در یک SpatialPanel (همانطور که در قطعه کد قبلی نشان داده شده است)، مدارگرد به آن SpatialPanel متصل می شود.
  • در یک Subspace ، مدارگرد به نزدیکترین موجودیت والد متصل می‌شود، که چیدمان فضایی است که مدارگرد در آن اعلام شده است.

مثال زیر نحوه لنگر انداختن یک مدارگرد را به یک ردیف فضایی نشان می دهد:

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

نکات کلیدی در مورد کد

  • وقتی مدارگردی را خارج از طرح دوبعدی اعلام می کنید، مدارگرد به نزدیکترین موجودیت اصلی خود متصل می شود. در این مورد، مدارگرد به بالای SpatialRow که در آن اعلام شده است لنگر می‌اندازد.
  • طرح‌بندی‌های فضایی مانند SpatialRow ، SpatialColumn ، SpatialBox همگی دارای موجودیت‌های بی محتوا هستند. بنابراین، یک مدارگرد اعلام شده در یک طرح فضایی به آن طرح لنگر می زند.

همچنین ببینید