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

इस पेज में, Glance के मौजूदा कॉम्पोनेंट का इस्तेमाल करके, Glance के लेआउट के साइज़ को मैनेज करने और उन्हें ज़रूरत के मुताबिक बनाने का तरीका बताया गया है.

Box, Column, और Row का इस्तेमाल करें

Glance में तीन मुख्य कॉम्पोज़ेबल लेआउट होते हैं:

  • Box: एलिमेंट को एक-दूसरे के ऊपर रखता है. इसका अनुवाद RelativeLayout में किया जाता है.

  • Column: वर्टिकल ऐक्सिस में, एलिमेंट को एक-दूसरे के बाद रखता है. यह वर्टिकल ओरिएंटेशन वाले LinearLayout में बदल जाता है.

  • Row: यह हॉरिज़ॉन्टल ऐक्सिस में, एलिमेंट को एक-दूसरे के बाद रखता है. यह हॉरिज़ॉन्टल ओरिएंटेशन वाले LinearLayout में बदल जाता है.

एक नज़र में जानकारी देखने की सुविधा, Scaffold ऑब्जेक्ट के साथ काम करती है. अपने Column, Row, और Box कॉम्पोज़ेबल को किसी दिए गए Scaffold ऑब्जेक्ट में डालें.

कॉलम, लाइन, और बॉक्स लेआउट की इमेज.
पहला डायग्राम. कॉलम, लाइन, और बॉक्स वाले लेआउट के उदाहरण.

इनमें से हर कॉम्पोनस की मदद से, कॉन्टेंट के वर्टिकल और हॉरिज़ॉन्टल अलाइनमेंट के साथ-साथ, चौड़ाई, ऊंचाई, वज़न या पैडिंग की सीमाएं तय की जा सकती हैं. इसके लिए, आपको मॉडिफ़ायर का इस्तेमाल करना होगा. इसके अलावा, हर बच्चा अपने मॉडिफ़ायर तय कर सकता है, ताकि पैरंट में स्पेस और प्लेसमेंट बदला जा सके.

नीचे दिए गए उदाहरण में, Row बनाने का तरीका बताया गया है. इसमें, इसके चाइल्ड एलिमेंट को हॉरिज़ॉन्टल तौर पर बराबर-बराबर बांटा गया है, जैसा कि पहले चित्र में दिखाया गया है:

Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) {
    val modifier = GlanceModifier.defaultWeight()
    Text("first", modifier)
    Text("second", modifier)
    Text("third", modifier)
}

Row, उपलब्ध चौड़ाई को पूरा भर देता है. साथ ही, हर बच्चे का वज़न एक जैसा होने की वजह से, वे उपलब्ध जगह को बराबर बांटते हैं. लेआउट को अपनी ज़रूरतों के हिसाब से बनाने के लिए, अलग-अलग वेट, साइज़, पैडिंग या अलाइनमेंट तय किए जा सकते हैं.

स्क्रोल किए जा सकने वाले लेआउट का इस्तेमाल करना

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

यहां दिए गए स्निपेट में, LazyColumn में आइटम तय करने के अलग-अलग तरीके दिखाए गए हैं.

आइटम की संख्या इस तरह दी जा सकती है:

// Remember to import Glance Composables
// import androidx.glance.appwidget.layout.LazyColumn

LazyColumn {
    items(10) { index: Int ->
        Text(
            text = "Item $index",
            modifier = GlanceModifier.fillMaxWidth()
        )
    }
}

अलग-अलग आइटम दें:

LazyColumn {
    item {
        Text("First Item")
    }
    item {
        Text("Second Item")
    }
}

आइटम की सूची या ऐरे दें:

LazyColumn {
    items(peopleNameList) { name ->
        Text(name)
    }
}

ऊपर दिए गए उदाहरणों को मिलाकर भी इस्तेमाल किया जा सकता है:

LazyColumn {
    item {
        Text("Names:")
    }
    items(peopleNameList) { name ->
        Text(name)
    }

    // or in case you need the index:
    itemsIndexed(peopleNameList) { index, person ->
        Text("$person at index $index")
    }
}

ध्यान दें कि पिछले स्निपेट में itemId के बारे में नहीं बताया गया है. itemId की जानकारी देने से, परफ़ॉर्मेंस को बेहतर बनाने और Android 12 के बाद की सूची और appWidget अपडेट के ज़रिए स्क्रोल की पोज़िशन को बनाए रखने में मदद मिलती है. उदाहरण के लिए, सूची में आइटम जोड़ने या हटाने के दौरान. यहां दिए गए उदाहरण में, itemId की जानकारी देने का तरीका बताया गया है:

items(items = peopleList, key = { person -> person.id }) { person ->
    Text(person.name)
}

इन पर भी लागू होती हैं.

SizeMode के बारे में बताएं

AppWidget डिवाइस, उपयोगकर्ता की पसंद या लॉन्चर के हिसाब से, विजेट के साइज़ अलग-अलग हो सकते हैं. इसलिए, विजेट के लिए अलग-अलग लेआउट उपलब्ध कराएं पेज पर बताए गए तरीके के हिसाब से, विजेट के लिए अलग-अलग लेआउट उपलब्ध कराना ज़रूरी है. एक नज़र में जानकारी देखने की सुविधा, SizeMode की परिभाषा और LocalSize की वैल्यू की मदद से, इस काम को आसान बनाती है. नीचे दिए गए सेक्शन में, तीन मोड के बारे में बताया गया है.

SizeMode.Single

SizeMode.Single डिफ़ॉल्ट मोड है. इससे पता चलता है कि सिर्फ़ एक तरह का कॉन्टेंट उपलब्ध है. इसका मतलब है कि AppWidget के उपलब्ध साइज़ में बदलाव होने पर भी, कॉन्टेंट का साइज़ नहीं बदलता.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Single

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the minimum size or resizable
        // size defined in the App Widget metadata
        val size = LocalSize.current
        // ...
    }
}

इस मोड का इस्तेमाल करते समय, पक्का करें कि:

  • कॉन्टेंट के साइज़ के आधार पर, मेटाडेटा वैल्यू का कम से कम और ज़्यादा से ज़्यादा साइज़ तय किया गया है.
  • कॉन्टेंट का साइज़, अनुमानित रेंज में हो.

आम तौर पर, आपको इस मोड का इस्तेमाल तब करना चाहिए, जब:

a) AppWidget का साइज़ तय होता है या b) साइज़ बदलने पर, उसका कॉन्टेंट नहीं बदलता.

SizeMode.Responsive

यह मोड, रिस्पॉन्सिव लेआउट उपलब्ध कराने के बराबर है. इससे GlanceAppWidget को रिस्पॉन्सिव लेआउट का एक सेट तय करने की अनुमति मिलती है, जो खास साइज़ के हिसाब से तय किया जाता है. तय किए गए हर साइज़ के लिए, कॉन्टेंट बनाया जाता है और AppWidget बनाने या अपडेट करने पर, उसे उस साइज़ से मैप किया जाता है. इसके बाद, सिस्टम उपलब्ध साइज़ के आधार पर, सबसे सही विकल्प चुनता है.

उदाहरण के लिए, हमारे डेस्टिनेशन AppWidget में, तीन साइज़ और उनके कॉन्टेंट को तय किया जा सकता है:

class MyAppWidget : GlanceAppWidget() {

    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

    override val sizeMode = SizeMode.Responsive(
        setOf(
            SMALL_SQUARE,
            HORIZONTAL_RECTANGLE,
            BIG_SQUARE
        )
    )

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be one of the sizes defined above.
        val size = LocalSize.current
        Column {
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            }
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width >= HORIZONTAL_RECTANGLE.width) {
                    Button("School")
                }
            }
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "provided by X")
            }
        }
    }
}

पिछले उदाहरण में, provideContent तरीके को तीन बार बुलाया गया है और इसे तय किए गए साइज़ से मैप किया गया है.

  • पहले कॉल में, साइज़ का आकलन 100x100 के तौर पर किया जाता है. कॉन्टेंट में, अतिरिक्त बटन और ऊपर और नीचे मौजूद टेक्स्ट शामिल नहीं हैं.
  • दूसरे कॉल में, साइज़ का आकलन 250x100 के तौर पर किया जाता है. कॉन्टेंट में एक अतिरिक्त बटन शामिल है, लेकिन ऊपर और नीचे मौजूद टेक्स्ट नहीं.
  • तीसरे कॉल में, साइज़ का आकलन 250x250 के तौर पर किया जाता है. कॉन्टेंट में, अतिरिक्त बटन और दोनों टेक्स्ट शामिल हैं.

SizeMode.Responsive, दूसरे दो मोड का कॉम्बिनेशन है. इससे, पहले से तय की गई सीमाओं के हिसाब से रिस्पॉन्सिव कॉन्टेंट तय किया जा सकता है. आम तौर पर, यह मोड बेहतर परफ़ॉर्म करता है. साथ ही, AppWidget का साइज़ बदलने पर, ट्रांज़िशन आसानी से होता है.

नीचे दी गई टेबल में, SizeMode और AppWidget के उपलब्ध साइज़ के आधार पर, साइज़ की वैल्यू दिखाई गई है:

उपलब्ध साइज़ 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Single 110 x 110 110 x 110 110 x 110 110 x 110
SizeMode.Exact 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Responsive 80 x 100 80 x 100 80 x 100 150 x 120
* सटीक वैल्यू सिर्फ़ डेमो के लिए हैं.

SizeMode.Exact

SizeMode.Exact, सही लेआउट उपलब्ध कराने के बराबर है. यह हर बार GlanceAppWidget कॉन्टेंट का अनुरोध करता है, जब उपलब्ध AppWidget का साइज़ बदलता है. उदाहरण के लिए, जब उपयोगकर्ता होमस्क्रीन में AppWidget का साइज़ बदलता है.

उदाहरण के लिए, अगर उपलब्ध चौड़ाई किसी तय वैल्यू से ज़्यादा है, तो डेस्टिनेशन विजेट में एक और बटन जोड़ा जा सकता है.

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Exact

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the size of the AppWidget
        val size = LocalSize.current
        Column {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width > 250.dp) {
                    Button("School")
                }
            }
        }
    }
}

यह मोड, अन्य मोड की तुलना में ज़्यादा सुविधाएं देता है. हालांकि, इसमें कुछ बातों का ध्यान रखना ज़रूरी है:

  • साइज़ में हर बार बदलाव होने पर, AppWidget को पूरी तरह से फिर से बनाया जाना चाहिए. कॉन्टेंट के जटिल होने पर, इससे परफ़ॉर्मेंस से जुड़ी समस्याएं आ सकती हैं और यूज़र इंटरफ़ेस (यूआई) में अचानक बदलाव हो सकता है.
  • लॉन्चर के लागू होने के तरीके के हिसाब से, उपलब्ध साइज़ अलग-अलग हो सकता है. उदाहरण के लिए, अगर लॉन्चर में साइज़ की सूची नहीं दी गई है, तो कम से कम साइज़ का इस्तेमाल किया जाता है.
  • Android 12 से पहले के डिवाइसों में, हो सकता है कि साइज़ का हिसाब लगाने का लॉजिक सभी स्थितियों में काम न करे.

आम तौर पर, आपको इस मोड का इस्तेमाल तब करना चाहिए, जब SizeMode.Responsive का इस्तेमाल न किया जा सके (यानी, रिस्पॉन्सिव लेआउट का छोटा सेट काम का न हो).

संसाधनों को ऐक्सेस करना

किसी भी Android संसाधन को ऐक्सेस करने के लिए, LocalContext.current का इस्तेमाल करें, जैसा कि इस उदाहरण में दिखाया गया है:

LocalContext.current.getString(R.string.glance_title)

हमारा सुझाव है कि फ़ाइनल RemoteViews ऑब्जेक्ट का साइज़ कम करने और डाइनैमिक रंग जैसे डाइनैमिक संसाधनों को चालू करने के लिए, सीधे तौर पर संसाधन आईडी दें.

कॉम्पोज़ेबल और तरीके, ImageProvider जैसे "प्रोवाइडर" का इस्तेमाल करके या GlanceModifier.background(R.color.blue) जैसे ओवरलोड तरीके का इस्तेमाल करके संसाधन स्वीकार करते हैं. उदाहरण के लिए:

Column(
    modifier = GlanceModifier.background(R.color.default_widget_background)
) { /**...*/ }

Image(
    provider = ImageProvider(R.drawable.ic_logo),
    contentDescription = "My image",
)

टेक्स्ट को हैंडल करना

Glance 1.1.0 में, टेक्स्ट स्टाइल सेट करने के लिए एपीआई शामिल है. TextStyle क्लास के fontSize, fontWeight या fontFamily एट्रिब्यूट का इस्तेमाल करके, टेक्स्ट स्टाइल सेट करें.

fontFamily सभी सिस्टम फ़ॉन्ट के साथ काम करता है, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है. हालांकि, ऐप्लिकेशन में कस्टम फ़ॉन्ट का इस्तेमाल नहीं किया जा सकता:

Text(
    style = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 18.sp,
        fontFamily = FontFamily.Monospace
    ),
    text = "Example Text"
)

कंपाउंड बटन जोड़ना

कंपाउंड बटन, Android 12 में लॉन्च किए गए थे. Glance, इस तरह के कंपाउंड बटन के साथ काम करता है:

इन कंपाउंड बटन में से हर बटन पर क्लिक किया जा सकता है. यह बटन, "चुनी गई" स्थिति दिखाता है.

var isApplesChecked by remember { mutableStateOf(false) }
var isEnabledSwitched by remember { mutableStateOf(false) }
var isRadioChecked by remember { mutableStateOf(0) }

CheckBox(
    checked = isApplesChecked,
    onCheckedChange = { isApplesChecked = !isApplesChecked },
    text = "Apples"
)

Switch(
    checked = isEnabledSwitched,
    onCheckedChange = { isEnabledSwitched = !isEnabledSwitched },
    text = "Enabled"
)

RadioButton(
    checked = isRadioChecked == 1,
    onClick = { isRadioChecked = 1 },
    text = "Checked"
)

स्थिति बदलने पर, दिया गया लैम्ब्डा फ़ंक्शन ट्रिगर हो जाता है. जांच की स्थिति को स्टोर किया जा सकता है, जैसा कि इस उदाहरण में दिखाया गया है:

class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        val myRepository = MyRepository.getInstance()

        provideContent {
            val scope = rememberCoroutineScope()

            val saveApple: (Boolean) -> Unit =
                { scope.launch { myRepository.saveApple(it) } }
            MyContent(saveApple)
        }
    }

    @Composable
    private fun MyContent(saveApple: (Boolean) -> Unit) {

        var isAppleChecked by remember { mutableStateOf(false) }

        Button(
            text = "Save",
            onClick = { saveApple(isAppleChecked) }
        )
    }
}

CheckBox, Switch, और RadioButton के रंगों को पसंद के मुताबिक बनाने के लिए, उनके लिए colors एट्रिब्यूट की वैल्यू भी सबमिट की जा सकती है:

CheckBox(
    // ...
    colors = CheckboxDefaults.colors(
        checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight),
        uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked }
)

Switch(
    // ...
    colors = SwitchDefaults.colors(
        checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan),
        uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta),
        checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow),
        uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked },
    text = "Enabled"
)

RadioButton(
    // ...
    colors = RadioButtonDefaults.colors(
        checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow),
        uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue)
    ),

)

अन्य कॉम्पोनेंट

Glance 1.1.0 में अन्य कॉम्पोनेंट भी रिलीज़ किए गए हैं. इनके बारे में नीचे दी गई टेबल में बताया गया है:

नाम इमेज रेफ़रंस लिंक अतिरिक्त नोट
भरा हुआ बटन alt_text कॉम्पोनेंट
आउटलाइन वाले बटन alt_text कॉम्पोनेंट
आइकॉन बटन alt_text कॉम्पोनेंट प्राइमरी / सेकंडरी / सिर्फ़ आइकॉन
टाइटल बार alt_text कॉम्पोनेंट
मचान स्कैफ़ोल्ड और टाइटल बार, एक ही डेमो में हैं.

डिज़ाइन की खास बातों के बारे में ज़्यादा जानने के लिए, Figma पर इस डिज़ाइन किट में कॉम्पोनेंट के डिज़ाइन देखें.

कैननिकल लेआउट के बारे में ज़्यादा जानने के लिए, कैननिकल विजेट लेआउट पर जाएं.