इस पेज पर, Glance के मौजूदा कॉम्पोनेंट का इस्तेमाल करके, साइज़ को मैनेज करने और Glance के साथ ज़रूरत के हिसाब से अडजस्ट होने वाले और रिस्पॉन्सिव लेआउट उपलब्ध कराने का तरीका बताया गया है.
Box, Column, और Row का इस्तेमाल करें
Glance में तीन मुख्य कंपोज़ेबल लेआउट होते हैं:
Box: एलिमेंट को एक-दूसरे के ऊपर रखता है. इसका मतलब है किRelativeLayout.Column: यह एलिमेंट को वर्टिकल ऐक्सिस में एक के बाद एक रखता है. इसका मतलब है किLinearLayoutको वर्टिकल ओरिएंटेशन में दिखाया जाता है.Row: एलिमेंट को हॉरिज़ॉन्टल ऐक्सिस में एक के बाद एक रखता है. इसका मतलब है कि हॉरिज़ॉन्टल ओरिएंटेशन वालेLinearLayoutका इस्तेमाल करें.
Glance में 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, itemId = { person -> person.id.hashCode().toLong() }) { person -> Text(person.name) }
स्नैप स्क्रोलिंग
स्नैप स्क्रोलिंग एक ऐनिमेशन है. इसकी मदद से, स्क्रोल किए जा सकने वाले कॉन्टेंट को विजेट कंटेनर के सबसे ऊपर स्नैप किया जा सकता है.
स्नैप स्क्रोलिंग की सुविधा लागू करने के लिए, पक्का करें कि आपने ये शर्तें पूरी की हों:
- Glance की डिपेंडेंसी को 1.3.0-alpha02 या इसके बाद के वर्शन पर अपडेट करें.
- अपने
compileSdkको 37 या इसके बाद के वर्शन पर सेट करें. ऐसा इसलिए, क्योंकि स्नैप स्क्रोलिंग की सुविधा, Android 17 और इसके बाद के वर्शन वाले डिवाइसों पर काम करती है. VerticalScrollModeकी मदद से, अपनेLazyColumnको कॉन्फ़िगर करें. अगर डिवाइस पर स्नैप स्क्रोलिंग की सुविधा काम करती है, तोSnapScrollMatchHeightका इस्तेमाल करें. अगर ऐसा नहीं है, तोNormalका इस्तेमाल करें.
अगर इमेज के साथ स्नैप स्क्रोलिंग का इस्तेमाल किया जा रहा है, तो फ़ुल ब्लीड इमेज कैननिकल लेआउट देखें.
@Composable fun SnapScrollLayout() { val height = LocalSize.current.height val items = listOf( ColorItem(Color.Red, "Red"), ColorItem(Color.Yellow, "Yellow"), ColorItem(Color.Blue, "Blue") ) val scrollMode = if (Build.VERSION.SDK_INT >= 37) { VerticalScrollMode.SnapScrollMatchHeight(height) } else { VerticalScrollMode.Normal } LazyColumn( verticalScrollMode = scrollMode ) { items(items) { item -> ColorCard(item, height) } } } @Composable private fun ColorCard(item: ColorItem, height: Dp) { Box( modifier = GlanceModifier .background(item.color) .fillMaxWidth() .height(height), contentAlignment = Alignment.Center ) { Text( text = item.name, modifier = GlanceModifier.background(Color.White) ) } }
SizeMode को परिभाषित करें
AppWidget के साइज़, डिवाइस, उपयोगकर्ता के लिए उपलब्ध विकल्प या लॉन्चर के हिसाब से अलग-अलग हो सकते हैं. इसलिए, विजेट के लिए ज़रूरत के हिसाब से अडजस्ट होने वाले लेआउट उपलब्ध कराना पेज पर बताए गए तरीके से, ज़रूरत के हिसाब से अडजस्ट होने वाले लेआउट उपलब्ध कराना ज़रूरी है. Glance, 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, सटीक लेआउट उपलब्ध कराने के बराबर है. यह हर बार उपलब्ध AppWidget साइज़ बदलने पर, GlanceAppWidget कॉन्टेंट का अनुरोध करता है. उदाहरण के लिए, जब उपयोगकर्ता होमस्क्रीन पर 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 { mutableIntStateOf(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) } ) } }
colors एट्रिब्यूट का इस्तेमाल करके, CheckBox, Switch, और RadioButton के रंगों को अपनी पसंद के मुताबिक बनाया जा सकता है:
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 में अतिरिक्त कॉम्पोनेंट की रिलीज़ शामिल है. इनके बारे में इस टेबल में बताया गया है:
| नाम | इमेज | रेफ़रंस लिंक | अतिरिक्त जानकारी |
|---|---|---|---|
| फ़िल्ड बटन |
|
कॉम्पोनेंट | |
| आउटलाइन बटन |
|
कॉम्पोनेंट | |
| आइकॉन बटन |
|
कॉम्पोनेंट | प्राइमरी / सेकंडरी / सिर्फ़ आइकॉन |
| टाइटल बार |
|
कॉम्पोनेंट | |
| मचान | Scaffold और टाइटल बार, एक ही डेमो में हैं. |
डिज़ाइन से जुड़ी खास जानकारी के लिए, Figma पर मौजूद इस डिज़ाइन किट में कॉम्पोनेंट के डिज़ाइन देखें.
कैननिकल लेआउट के बारे में ज़्यादा जानने के लिए, कैननिकल विजेट लेआउट पर जाएं.