XR के लिए Jetpack Compose की मदद से यूज़र इंटरफ़ेस (यूआई) बनाना

XR के लिए Jetpack Compose की मदद से, Compose के जाने-पहचाने कॉन्सेप्ट, जैसे कि पंक्तियों और कॉलम का इस्तेमाल करके, स्पेसिएल यूआई और लेआउट को आसानी से बनाया जा सकता है. इसकी मदद से, अपने मौजूदा Android यूज़र इंटरफ़ेस (यूआई) को 3D स्पेस में बढ़ाया जा सकता है या पूरी तरह से नए इमर्सिव 3D ऐप्लिकेशन बनाए जा सकते हैं.

अगर आपको किसी मौजूदा Android Views-आधारित ऐप्लिकेशन को स्पेसिएलाइज़ करना है, तो आपके पास डेवलपमेंट के कई विकल्प हैं. इंटरऑपरेबिलिटी एपीआई का इस्तेमाल किया जा सकता है, Compose और व्यू को एक साथ इस्तेमाल किया जा सकता है या सीधे तौर पर SceneCore लाइब्रेरी का इस्तेमाल किया जा सकता है. ज़्यादा जानकारी के लिए, व्यू के साथ काम करने के लिए गाइड देखें.

सबस्पेस और स्पेसलाइज़ किए गए कॉम्पोनेंट के बारे में जानकारी

Android XR के लिए ऐप्लिकेशन लिखते समय, सबस्पेस और स्पेशलाइज़्ड कॉम्पोनेंट के कॉन्सेप्ट को समझना ज़रूरी है.

सबस्पेस के बारे में जानकारी

Android XR के लिए डेवलप करते समय, आपको अपने ऐप्लिकेशन या लेआउट में सबस्पेस जोड़ना होगा. सबस्पेस, आपके ऐप्लिकेशन में मौजूद 3D स्पेस का एक हिस्सा होता है. इसमें 3D कॉन्टेंट डाला जा सकता है, 3D लेआउट बनाए जा सकते हैं, और 2D कॉन्टेंट में डीपथ जोड़ी जा सकती है. सबस्पेस सिर्फ़ तब रेंडर होता है, जब स्पेसलाइज़ेशन की सुविधा चालू हो. होम स्पेस या नॉन-एक्सआर डिवाइसों पर, उस सबस्पेस में मौजूद किसी भी कोड को अनदेखा कर दिया जाता है.

सबस्पेस बनाने के दो तरीके हैं:

  • setSubspaceContent(): यह फ़ंक्शन, ऐप्लिकेशन-लेवल का सबस्पेस बनाता है. इसे अपनी मुख्य गतिविधि में उसी तरह से कॉल किया जा सकता है जिस तरह setContent() का इस्तेमाल किया जाता है. ऐप्लिकेशन-लेवल सबस्पेस की ऊंचाई, चौड़ाई, और गहराई में कोई सीमा नहीं होती. यह स्पेसऐटल कॉन्टेंट के लिए, अनलिमिटेड कैनवस उपलब्ध कराता है.
  • Subspace: इस कॉम्पोज़ेबल को ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) के लेआउट में कहीं भी रखा जा सकता है. इससे, फ़ाइलों के बीच कॉन्टेक्स्ट को खोए बिना, 2D और स्पेस यूज़र इंटरफ़ेस (यूआई) के लिए लेआउट बनाए जा सकते हैं. इससे, XR और अन्य डिवाइसों के नाप या आकार के बीच, ऐप्लिकेशन के मौजूदा आर्किटेक्चर जैसी चीज़ों को आसानी से शेयर किया जा सकता है. इसके लिए, आपको अपने पूरे यूज़र इंटरफ़ेस (यूआई) ट्री में स्टेटस को होस्ट करने या अपने ऐप्लिकेशन का आर्किटेक्चर फिर से बनाने की ज़रूरत नहीं होती.

ज़्यादा जानकारी के लिए, अपने ऐप्लिकेशन में सबस्पेस जोड़ना लेख पढ़ें.

स्पेसलाइज़ किए गए कॉम्पोनेंट के बारे में जानकारी

सबस्पेस कॉम्पोनेंट: इन कॉम्पोनेंट को सिर्फ़ सबस्पेस में रेंडर किया जा सकता है. इन्हें 2D लेआउट में डालने से पहले, Subspace या setSubspaceContent में डालना होगा. SubspaceModifier की मदद से, सबस्पेस कॉम्पोज़ेबल में डेप्थ, ऑफ़सेट, और पोज़िशनिंग जैसे एट्रिब्यूट जोड़े जा सकते हैं.

स्पेस में दिखाए जाने वाले अन्य कॉम्पोनेंट को सबस्पेस में कॉल करने की ज़रूरत नहीं होती. इनमें, स्पेस कंटेनर में मौजूद सामान्य 2D एलिमेंट होते हैं. अगर इन एलिमेंट को 2D और 3D, दोनों लेआउट के लिए तय किया गया है, तो इनका इस्तेमाल 2D या 3D लेआउट में किया जा सकता है. जब स्पेशलाइज़ेशन की सुविधा चालू नहीं होती, तो स्पेशलाइज़ की गई सुविधाओं को अनदेखा कर दिया जाता है और वे 2D वर्शन में दिखती हैं.

स्पेस पैनल बनाना

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 या setSubspaceContent में कॉल करना होगा. किसी सबस्पेस के बाहर इन फ़ंक्शन को कॉल करने पर, अपवाद दिखता है.
  • उपयोगकर्ता को पैनल का साइज़ बदलने या उसे एक जगह से दूसरी जगह ले जाने की अनुमति दें. इसके लिए, movable या resizable मॉडिफ़ायर जोड़ें.
  • साइज़ और प्लेसमेंट के बारे में जानने के लिए, स्पेशल पैनल के डिज़ाइन से जुड़े दिशा-निर्देश देखें. कोड लागू करने के बारे में ज़्यादा जानकारी के लिए, हमारा रेफ़रंस दस्तावेज़ देखें.

मूव किए जा सकने वाले सबस्पेस मॉडिफ़ायर के काम करने का तरीका

जब कोई उपयोगकर्ता किसी पैनल को अपने से दूर ले जाता है, तो डिफ़ॉल्ट रूप से, पैनल को छोटा या बड़ा करने वाला सबस्पेस मॉडिफ़ायर, उसी तरह से पैनल का साइज़ बदलता है जिस तरह से होम स्पेस में सिस्टम, पैनल का साइज़ बदलता है. बच्चों के लिए बने सभी कॉन्टेंट पर यह सेटिंग लागू होती है. इसे बंद करने के लिए, scaleWithDistance पैरामीटर को false पर सेट करें.

ऑर्बिटर बनाना

ऑर्बिटर, स्पेस यूज़र इंटरफ़ेस (यूआई) का कॉम्पोनेंट है. इसे, उसी तरह के स्पेस पैनल, लेआउट या किसी दूसरी इकाई से जोड़ा जाता है. आम तौर पर, ऑर्बिटर में उस इकाई से जुड़े नेविगेशन और संदर्भ के हिसाब से कार्रवाई करने वाले आइटम होते हैं जिससे इसे ऐंकर किया गया है. उदाहरण के लिए, अगर आपने वीडियो कॉन्टेंट दिखाने के लिए स्पेस पैनल बनाया है, तो ऑर्बिटर में वीडियो चलाने के कंट्रोल जोड़े जा सकते हैं.

ऑर्बिटर का उदाहरण

नीचे दिए गए उदाहरण में दिखाए गए तरीके से, नेविगेशन जैसे उपयोगकर्ता कंट्रोल को रैप करने के लिए, SpatialPanel में 2D लेआउट के अंदर ऑर्बिटर को कॉल करें. ऐसा करने पर, उन्हें आपके 2D लेआउट से निकाला जाता है और आपके कॉन्फ़िगरेशन के हिसाब से स्पेस पैनल में जोड़ दिया जाता है.

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

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

कोड के बारे में अहम जानकारी

  • ऑर्बिटर, स्पेस वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट होते हैं. इसलिए, कोड का फिर से इस्तेमाल 2D या 3D लेआउट में किया जा सकता है. 2D लेआउट में, आपका ऐप्लिकेशन सिर्फ़ ऑर्बिटर के अंदर मौजूद कॉन्टेंट को रेंडर करता है और ऑर्बिटर को अनदेखा करता है.
  • ऑर्बिटर का इस्तेमाल करने और डिज़ाइन करने के तरीके के बारे में ज़्यादा जानकारी के लिए, डिज़ाइन से जुड़े दिशा-निर्देश देखें.

स्पेसिएल लेआउट में कई स्पेसिएल पैनल जोड़ना

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 का इस्तेमाल करें.
  • एक पंक्ति में कई पैनल वाले लेआउट के लिए, हमारा सुझाव है कि आप SubspaceModifier का इस्तेमाल करके, कर्व रेडियस को 825dp पर सेट करें, ताकि पैनल आपके उपयोगकर्ता के चारों ओर हो जाएं. ज़्यादा जानकारी के लिए, डिज़ाइन से जुड़ी गाइड देखें.

अपने लेआउट में 3D ऑब्जेक्ट डालने के लिए, वॉल्यूम का इस्तेमाल करना

अपने लेआउट में 3D ऑब्जेक्ट डालने के लिए, आपको वॉल्यूम नाम के सबस्पेस कॉम्पोज़ेबल का इस्तेमाल करना होगा. इसका उदाहरण यहां दिया गया है.

लेआउट में 3D ऑब्जेक्ट का उदाहरण

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

ज़्यादा जानकारी

इमेज या वीडियो कॉन्टेंट के लिए प्लैटफ़ॉर्म जोड़ना

SpatialExternalSurface एक सबस्पेस कॉम्पोज़ेबल है. यह Surface बनाता और मैनेज करता है. इसमें आपका ऐप्लिकेशन कॉन्टेंट डाल सकता है, जैसे कि इमेज या वीडियो. SpatialExternalSurface स्टीरियोस्कोपिक या मोनोस्कोपिक, दोनों तरह के कॉन्टेंट के साथ काम करता है.

इस उदाहरण में, Media3 Exoplayer और SpatialExternalSurface का इस्तेमाल करके, एक साथ दिखने वाले स्टीरियोस्कोपिक वीडियो को लोड करने का तरीका बताया गया है:

@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 बदलावों को ऐप्लिकेशन रेंडरिंग या वीडियो डिकोडिंग के साथ सिंक नहीं किया जा सकता.
  • यह कॉम्पोज़ेबल, दूसरे पैनल के सामने रेंडर नहीं हो सकता. इसलिए, अगर लेआउट में दूसरे पैनल हैं, तो आपको मूव किए जा सकने वाले मॉडिफ़ायर का इस्तेमाल नहीं करना चाहिए.

स्पेस वाले अन्य यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट जोड़ना

स्पेस वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को आपके ऐप्लिकेशन के यूआई की हैरारकी में कहीं भी रखा जा सकता है. इन एलिमेंट का इस्तेमाल, आपके 2D यूज़र इंटरफ़ेस (यूआई) में फिर से किया जा सकता है. साथ ही, इनके स्पेस एट्रिब्यूट सिर्फ़ तब दिखेंगे, जब स्पेस की सुविधाएं चालू होंगी. इससे, कोड को दो बार लिखे बिना ही, मेन्यू, डायलॉग, और अन्य कॉम्पोनेंट में ऊंचाई जोड़ी जा सकती है. इन एलिमेंट को इस्तेमाल करने का तरीका बेहतर तरीके से समझने के लिए, स्पेसिएल यूज़र इंटरफ़ेस के ये उदाहरण देखें.

यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट

स्पेशलाइज़ेशन की सुविधा चालू होने पर

2D एनवायरमेंट में

SpatialDialog

पैनल को ज़्यादा ऊंचाई पर दिखाने के लिए, पैनल को z-depth में थोड़ा पीछे धकेला जाएगा

2D Dialog पर वापस ले जाता है.

SpatialPopup

पैनल, ज़्यादा ऊंचाई वाला पॉप-अप दिखाने के लिए, z-depth में थोड़ा पीछे धकेल दिया जाएगा

2D Popup पर वापस आ जाता है.

SpatialElevation

SpatialElevationLevel को ऊंचाई जोड़ने के लिए सेट किया जा सकता है.

ऐसे शो जिनमें स्पेस एलिवेशन नहीं है.

SpatialDialog

यह ऐसे डायलॉग का उदाहरण है जो कुछ देर बाद खुलता है. SpatialDialog का इस्तेमाल करने पर, डायलॉग बॉक्स उसी z-depth पर दिखता है जिस पर स्पेस पैनल दिखता है. साथ ही, स्पेसलाइज़ेशन चालू होने पर, पैनल को 125dp पीछे धकेल दिया जाता है. स्पेशलाइज़ेशन की सुविधा चालू न होने पर भी SpatialDialog का इस्तेमाल किया जा सकता है. ऐसे में, SpatialDialog अपने 2D वर्शन, Dialog पर वापस आ जाता है.

@Composable
fun DelayedDialog() {
    var showDialog by remember { mutableStateOf(false) }
    LaunchedEffect(Unit) {
        delay(3000)
        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 में काम न करने वाले कस्टम पैनल बनाने के लिए, SceneCore एपीआई का इस्तेमाल करके, सीधे PanelEntities और सीन ग्राफ़ के साथ काम किया जा सकता है.

स्पेसिएल लेआउट और अन्य इकाइयों पर ऑर्बिटर को ऐंकर करना

Compose में बताई गई किसी भी इकाई पर ऑर्बिटर को ऐंकर किया जा सकता है. इसमें, SpatialRow, SpatialColumn या SpatialBox जैसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट के स्पेस लेआउट में ऑर्बिटर का एलान करना शामिल है. ऑर्बिटर, उस पैरंट इकाई से जुड़ जाता है जो आपके तय किए गए पॉइंट के सबसे करीब है.

ऑर्बिटर का व्यवहार इस बात से तय होता है कि आपने उसे कहां दिखाया है:

  • SpatialPanel में रैप किए गए 2D लेआउट में (जैसा कि पिछले कोड स्निपेट में दिखाया गया है), ऑर्बिटर उस SpatialPanel पर ऐंकर होता है.
  • Subspace में, ऑर्बिटर सबसे नज़दीकी पैरंट इकाई से जुड़ा होता है. यह वह स्पेस लेआउट होता है जिसमें ऑर्बिटर का एलान किया जाता है.

यहां दिए गए उदाहरण में, ऑर्बिटर को स्पेस वाली लाइन में ऐंकर करने का तरीका बताया गया है:

Subspace {
    SpatialRow {
        Orbiter(
            position = OrbiterEdge.Top,
            offset = EdgeOffset.inner(8.dp),
            shape = SpatialRoundedCornerShape(size = CornerSize(50))
        ) {
            Text(
                "Hello World!",
                style = MaterialTheme.typography.h2,
                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)
            )
        }
    }
}

कोड के बारे में अहम जानकारी

  • जब किसी ऑर्बिटर को 2D लेआउट के बाहर दिखाया जाता है, तो वह ऑर्बिटर अपनी सबसे नज़दीकी पैरंट इकाई से जुड़ जाता है. इस मामले में, ऑर्बिटर उस SpatialRow के सबसे ऊपर अटैच हो जाता है जिसमें उसे एलान किया गया है.
  • SpatialRow, SpatialColumn, SpatialBox जैसे स्पेस वाले लेआउट में, कॉन्टेंट वाली इकाइयां नहीं होती हैं. इसलिए, स्पेस लेआउट में एलान किया गया ऑर्बिटर, उस लेआउट में ऐंकर होता है.

यह भी देखें: