توسعه میانای کاربر فضایی با Jetpack Compose برای XR

دستگاه‌های XR قابل‌اعمال
این راهنمایی به شما کمک می‌کند برای این نوع دستگاه‌های واقعیت گسترده تجربه بسازید.
هدست‌های واقعیت گسترده
عینک واقعیت گسترده سیمی

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

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

درباره زیرفضاها و عناصر فضایی

وقتی برنامه خود را برای Android XR می‌نویسید، مهم است که مفاهیم فضای فرعی و عناصر فضایی‌سازی‌شده را درک کنید.

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

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

چند روش برای ایجاد یک فضای زیرین وجود دارد:

  • Subspace: این عنصر ترکیبی سلسله‌مراتب جدید و مستقلی برای «میانای کاربری فضایی» ایجاد می‌کند. موقعیت فضایی، جهت، یا مقیاس هیچ Subspace والدینی را که در آن تودرتو است به ارث نمی‌برد. Subspace به‌طور خودکار به چارگوش محتوای توصیه‌شده سیستم محدود می‌شود.
  • PlanarEmbeddedSubspace: این عنصر ترکیبی می‌تواند در سلسله‌مراتب واسط کاربر برنامه شما قرار گیرد و به شما امکان می‌دهد چیدمان‌های واسط کاربر فضایی و دوبعدی را حفظ کنید. ‫PlanarEmbeddedSubspace محدودیت‌ها و جایگاه‌سازی ولی‌اش را رعایت می‌کند. محتوای سه‌بعدی که در داخل آن قرار می‌گیرد، نسبت به این ناحیه تعریف‌شده دوبعدی موقعیت‌یابی می‌شود.

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

درباره عناصر فضایی‌سازی‌شده

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

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

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

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

نمونه‌ای از پانل رابط کاربری فضایی

می‌توانید از SubspaceModifier برای تغییر اندازه، رفتار، و موقعیت پانل فضایی استفاده کنید، همان‌طور که در مثال زیر نشان داده شده است.

Subspace {
    SpatialPanel(
        SubspaceModifier
            .height(824.dp)
            .width(1400.dp)
            .movable()
            .resizable(),
    ) {
        SpatialPanelContent()
    }
}

@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 ترکیب‌پذیرهای فضای فرعی هستند، باید آن‌ها را در Subspace فراخوانی کنید. فراخوانی آن‌ها در خارج از فضای فرعی استثنا ایجاد می‌کند.
  • اندازه SpatialPanel بااستفاده از مشخصات height و width در SubspaceModifier تنظیم شده است. با حذف این مشخصات، اندازه پانل براساس اندازه‌های محتوای آن تعیین می‌شود.
  • با افزودن اصلاح‌گر فضای فرعی movable، به کاربر اجازه دهید پانل را جابه‌جا کند.
  • با افزودن اصلاح‌گر resizable فضای فرعی به کاربر اجازه دهید اندازه پانل را تغییر دهد.
  • برای جزئیات مربوط به اندازه‌بندی و موقعیت‌یابی، راهنمایی طراحی پانل فضایی ما را ببینید. برای اطلاعات دقیق‌تر درباره پیاده‌سازی کد، به اسناد مرجع ما مراجعه کنید.

نحوه عملکرد اصلاح‌کننده movable

وقتی کاربر پانلی را از خود دور می‌کند، به‌طور پیش‌فرض، اصلاح‌گر movable پانل را به روشی مشابه با نحوه تغییر اندازه پانل‌ها توسط سیستم در فضای خانه مقیاس‌بندی می‌کند. همه محتوای کودکان این رفتار را به ارث می‌برند. برای غیرفعال کردن این ویژگی، پارامتر shouldScaleWithDistance را روی false تنظیم کنید.

ایجاد مدارگرد

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

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

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

Subspace {
    SpatialPanel(
        SubspaceModifier
            .height(824.dp)
            .width(1400.dp)
            .resizable()
            .movable(),
    ) {
        SpatialPanelContent()
        OrbiterExample()
    }
}

@Composable
fun OrbiterExample() {
    Orbiter(
        alignment = OrbiterAlignment.BottomCenter(
            edgeOffsetType = OrbiterEdgeOffsetType.OuterEdge,
            offset = DpVolumeOffset(y = 96.dp)
        ),
    ) {
        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، و SpatialSpacer قرار دهید.

نمونه‌ای از چند پانل فضایی در چیدمان فضایی

مثال کد زیر نحوه انجام این کار را نشان می‌دهد.

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، و SpatialSpacer همگی عناصر ترکیبی فضای فرعی هستند و باید در فضای فرعی قرار داده شوند.
  • از SubspaceModifier برای سفارشی‌سازی چیدمان استفاده کنید.
  • برای چیدمان‌هایی که چند پانل در یک ردیف دارند، توصیه می‌کنیم بااستفاده از SubspaceModifier شعاع منحنی ۸۲۵dp تنظیم کنید تا پانل‌ها کاربرتان را احاطه کنند. برای جزئیات، راهنمایی طراحی ما را ببینید.

بااستفاده از SpatialGltfModel، شیء سه‌بعدی به چیدمانتان اضافه کنید

‫Android XR از قالب glTF برای مدل‌های سه‌بعدی پشتیبانی می‌کند که معمولاً به‌صورت فایل‌های .glb ذخیره می‌شوند. برای افزودن این اشیا به چیدمان، باید از SpatialGltfModel قابل ترکیب استفاده کنید. این API فرایند بار کردن دارایی‌ها و مدیریت وضعیت آن‌ها را ساده می‌کند.

برای نمایش مدل، ابتدا منبع و وضعیت آن را بااستفاده از rememberSpatialGltfModelState تعریف کنید. می‌توانید مدل‌ها را از پوشه assets برنامه، URI، یا raw data بار کنید.

val modelState = rememberSpatialGltfModelState(
    source = SpatialGltfModelSource.fromPath(
        Paths.get("models/model_name.glb")
    )
)

پس‌از تعریف وضعیت، از عنصر ترکیبی SpatialGltfModel برای پرداز کردن آن در «فضای فرعی» استفاده کنید.

SpatialGltfModel(state = modelState, modifier = SubspaceModifier)

نکات کلیدی درباره کد

  • بار کردن ناهمگام: مدل به‌صورت ناهمگام بار می‌شود. درطول ترکیب اولیه، اندازه ذاتی آن ممکن است صفر باشد؛ وقتی مدل آماده شد، چیدمان دوباره اندازه‌گیری می‌کند.
  • کنترل وضعیت: از SpatialGltfModelState.status برای پُرسمان وضعیت بارگیری یا برای کنترل پویانمایی‌ها استفاده کنید.
  • اندازه‌گیری و مقیاس‌بندی: به‌طور پیش‌فرض، اندازه چیدمان با چارگوش محدودکننده دارایی مطابقت دارد. می‌توانید با SubspaceModifier.size این تنظیم را ملغی کنید تا مدل به‌طور یکنواخت مقیاس‌بندی شود و در محدوده مشخص‌شده قرار بگیرد.

از SceneCoreEntity برای قرار دادن نهادها در چیدمان استفاده کنید

ترکیب‌پذیر SceneCoreEntity کتابخانه‌های Jetpack SceneCore و Compose for XR را به‌هم متصل می‌کند تا بتوانید از نهادهای ساخته‌شده با SceneCore در چیدمان‌های Compose استفاده کنید. این به شما امکان می‌دهد نهادهای سطح پایین‌تر و عناصر سفارشی بسازید و درعین‌حال به Compose اجازه دهید اندازه، موقعیت، تغییر والدین، افزودن فرزندان، و اعمال اصلاح‌کننده‌ها را روی آن نهادها انجام دهد.

val virtualPixelDensity = session.scene.virtualPixelDensity

Subspace {
    SceneCoreEntity(
        modifier = SubspaceModifier.offset(x = 50.dp),
        factory = {
            SurfaceEntity.create(
                session = session,
                pose = Pose.Identity,
                stereoMode = SurfaceEntity.StereoMode.MONO
            )
        },
        update = { entity ->
            // Compose state changes may be applied to the SceneCore entity here.
            entity.stereoMode = SurfaceEntity.StereoMode.SIDE_BY_SIDE
        },
        sizeAdapter =
            object : SceneCoreEntitySizeAdapter<SurfaceEntity> {
                override fun onLayoutSizeChanged(
                    entity: SurfaceEntity,
                    size: IntVolumeSize
                ) {
                    val extents = FloatSize2d(
                        size.width.toFloat(),
                        size.height.toFloat()
                    )
                    entity.shape = SurfaceEntity.Shape.Quad(extents)
                }
            },
    ) {
        // Content here will be children of the SceneCoreEntity
        // in the scene graph.
    }
}

نکات کلیدی درباره کد

  • واحد کارخانه‌ای: واحد کارخانه‌ای جایی است که نهاد زیرین SceneCore را مقداردهی اولیه می‌کنید.
  • واحد به‌روزرسانی: از واحد به‌روزرسانی برای اصلاح کردن دارایی‌های نهاد در پاسخ به تغییرات در وضعیت «نوشتن» استفاده کنید.
  • «تطبیق اندازه»: sizeAdapter ابعاد نهاد را به سیستم چیدمان «نگارش» برمی‌گرداند.

اطلاعات بیشتر

سطحی برای محتوای تصویری یا ویدیویی اضافه کنید

SpatialExternalSurface یک فضای فرعی قابل ترکیب است که Surface را ایجاد و مدیریت می‌کند و برنامه شما می‌تواند در آن محتوا، مانند تصویر یا ویدیو، بکشد. SpatialExternalSurface از محتوای استریوسکوپی یا مونوسکوپی پشتیبانی می‌کند.

این مثال نشان می‌دهد که چگونه ویدیو استریوسکوپی پهلوبه‌پهلو را بااستفاده از Media3 Exoplayer و SpatialExternalSurface بار کنید:

@OptIn(ExperimentalComposeApi::class)
@Composable
fun SpatialExternalSurfaceContent() {
    val context = LocalContext.current
    Subspace {
        SpatialExternalSurface(
            modifier = SubspaceModifier
                .width(1200.dp) // Default width is 400.dp if no width modifier is specified
                .height(676.dp), // Default height is 400.dp if no height modifier is specified
            // Use StereoMode.Mono, StereoMode.SideBySide, or StereoMode.TopBottom, depending
            // upon which type of content you are rendering: monoscopic content, side-by-side stereo
            // content, or top-bottom stereo content
            stereoMode = StereoMode.SideBySide,
        ) {
            val exoPlayer = remember { ExoPlayer.Builder(context).build() }
            val videoUri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                // Represents a side-by-side stereo video, where each frame contains a pair of
                // video frames arranged side-by-side. The frame on the left represents the left
                // eye view, and the frame on the right represents the right eye view.
                .path("sbs_video.mp4")
                .build()
            val mediaItem = MediaItem.fromUri(videoUri)

            // onSurfaceCreated is invoked only one time, when the Surface is created
            onSurfaceCreated { surface ->
                exoPlayer.setVideoSurface(surface)
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.prepare()
                exoPlayer.play()
            }
            // onSurfaceDestroyed is invoked when the SpatialExternalSurface composable and its
            // associated Surface are destroyed
            onSurfaceDestroyed { exoPlayer.release() }
        }
    }
}

نکات کلیدی درباره کد

  • StereoMode را بسته به نوع محتوایی که ارائه می‌کنید روی Mono،‏ SideBySide، یا TopBottom تنظیم کنید:
    • Mono: تصویر یا قاب ویدیو از یک تصویر یکسان تشکیل شده است که به هر دو چشم نشان داده می‌شود.
    • SideBySide: قاب تصویر یا ویدیو حاوی یک جفت تصویر یا قاب ویدیو است که در کنار هم چیده شده‌اند، جایی که تصویر یا قاب در سمت چپ نمای چشم چپ را نشان می‌دهد و تصویر یا قاب در سمت راست نمای چشم راست را نشان می‌دهد.
    • ‫TopBottom: قاب تصویر یا ویدیو حاوی یک جفت تصویر یا قاب ویدیو است که به‌صورت عمودی روی هم چیده شده‌اند، به‌طوری‌که تصویر یا قاب در بالا نمای چشم چپ را نشان می‌دهد و تصویر یا قاب در پایین نمای چشم راست را نشان می‌دهد.
  • SpatialExternalSurface فقط از سطوح مستطیلی پشتیبانی می‌کند.
  • این Surface رویدادهای ورودی را ضبط نمی‌کند.
  • همگام‌سازی تغییرات StereoMode با پردازش برنامه یا کدبندی ویدیو امکان‌پذیر نیست.
  • این عنصر ترکیبی نمی‌تواند در جلوی پانل‌های دیگر پرداز شود، بنابراین اگر پانل‌های دیگری در چیدمان وجود دارد، نباید از MovePolicy استفاده کنید.

سطحی برای محتوای ویدیویی محافظت‌شده با مدیریت حقوق دیجیتال اضافه کنید

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

برای ایجاد سطح امن، پارامتر SpatialExternalSurfaceProtection را در SpatialExternalSurfaceProtection.Protected در SpatialExternalSurface قابل ترکیب تنظیم کنید. علاوه‌براین، باید Media3 Exoplayer را با اطلاعات DRM مناسب پیکربندی کنید تا بتواند دریافت پروانه از سرور پروانه را مدیریت کند.

مثال زیر نحوه پیکربندی SpatialExternalSurface و ExoPlayer برای پخش جاری‌سازی ویدیویی محافظت‌شده با DRM را نشان می‌دهد:

@OptIn(ExperimentalComposeApi::class)
@Composable
fun DrmSpatialVideoPlayer() {
    val context = LocalContext.current
    Subspace {
        SpatialExternalSurface(
            modifier = SubspaceModifier
                .width(1200.dp)
                .height(676.dp),
            stereoMode = StereoMode.SideBySide,
            surfaceProtection = SpatialExternalSurfaceProtection.Protected
        ) {
            val exoPlayer = remember { ExoPlayer.Builder(context).build() }

            // Define the URI for your DRM-protected content and license server.
            val videoUri = "https://your-content-provider.com/video.mpd"
            val drmLicenseUrl = "https://your-license-server.com/license"

            // Build a MediaItem with the necessary DRM configuration.
            val mediaItem = MediaItem.Builder()
                .setUri(videoUri)
                .setDrmConfiguration(
                    MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
                        .setLicenseUri(drmLicenseUrl)
                        .build()
                )
                .build()

            onSurfaceCreated { surface ->
                // The created surface is secure and can be used by the player.
                exoPlayer.setVideoSurface(surface)
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.prepare()
                exoPlayer.play()
            }

            onSurfaceDestroyed { exoPlayer.release() }
        }
    }
}

نکات کلیدی درباره کد

  • «سطح محافظت‌شده»: تنظیم surfaceProtection = SpatialExternalSurfaceProtection.Protected در SpatialExternalSurface ضروری است تا Surface زیربنایی با بافرهای امن مناسب برای محتوای «مدیریت حقوق دیجیتال» پشتیبانی شود.
  • پیکربندی DRM: باید MediaItem را با طرح DRM (برای مثال، C.WIDEVINE_UUID) و نشانی وب سرور پروانه خود پیکربندی کنید. ‫ExoPlayer از این اطلاعات برای مدیریت جلسه DRM استفاده می‌کند.
  • محتوای امن: هنگام پردازش در یک سطح محافظت‌شده، محتوای ویدیو رمزگشایی و در یک مسیر امن نمایش داده می‌شود که به برآورده کردن الزامات پروانه محتوا کمک می‌کند. این کار همچنین از نمایش محتوا در نماگرفت‌های صفحه‌نمایش جلوگیری می‌کند.

افزودن عناصر دیگر واسط کاربر فضایی

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

عنصر میانای کاربر

وقتی فضاسازی فعال باشد

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

SpatialDialog

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

به دوبعدی برمی‌گردد Dialog.

SpatialPopup

پانل کمی در عمق z به عقب می‌رود تا بالاپر برجسته‌ای نمایش دهد

به Popup دوبعدی برمی‌گردد.

SpatialElevation

‫SpatialElevationLevel را می‌توان برای افزودن ارتفاع تنظیم کرد.

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

SpatialDialog

این نمونه‌ای از کادر گفتگویی است که پس‌از تأخیری کوتاه باز می‌شود. وقتی از SpatialDialog استفاده می‌شود، کادر گفتگو در همان عمق z پانل فضایی ظاهر می‌شود و وقتی فضاسازی فعال باشد، پانل ۱۲۵dp به عقب رانده می‌شود. همچنین می‌توان از SpatialDialog زمانی که فضاسازی فعال نیست استفاده کرد، در این صورت SpatialDialog به همتای دوبعدی خود، Dialog، برمی‌گردد.

@Composable
fun DelayedDialog() {
    var showDialog by remember { mutableStateOf(false) }
    LaunchedEffect(Unit) {
        delay(3000.milliseconds)
        showDialog = true
    }
    if (showDialog) {
        SpatialDialog(
            onDismissRequest = { showDialog = false },
            SpatialDialogProperties(
                dismissOnBackPress = true
            )
        ) {
            Box(
                Modifier
                    .height(150.dp)
                    .width(150.dp)
            ) {
                Button(onClick = { showDialog = false }) {
                    Text("OK")
                }
            }
        }
    }
}

نکات کلیدی درباره کد

ایجاد چیدمان‌ها و پانل‌های سفارشی

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

گردشگرهای لنگر را به چیدمان‌ها و پانل‌های فضایی اضافه کنید

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

عملکرد چرخان براساس جایی که آن را اعلام می‌کنید تعیین می‌شود:

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

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

Subspace {
    SpatialRow {
        Orbiter(
            alignment = OrbiterAlignment.TopCenter(
                edgeOffsetType = OrbiterEdgeOffsetType.OuterEdge,
                offset = DpVolumeOffset(y = 8.dp)
            ),
            shape = SpatialRoundedCornerShape(size = CornerSize(50))
        ) {
            Text(
                "Hello World!",
                style = MaterialTheme.typography.titleMedium,
                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 همه دارای نهادهای بدون محتوای مرتبط با خود هستند. بنابراین، یک چرخان که در چیدمان فضایی اعلام شده است به آن چیدمان متصل می‌شود.

همچنین مراجعه کنید به