विजेट के हिसाब से लेआउट उपलब्ध कराएं

लिखने की सुविधा आज़माएं
Android के लिए, Jetpack Compose को यूज़र इंटरफ़ेस (यूआई) टूलकिट के तौर पर इस्तेमाल करने का सुझाव दिया जाता है. Compose-style API का इस्तेमाल करके विजेट बनाने का तरीका जानें.

इस पेज पर, Android 12 (एपीआई लेवल 31) में शुरू की गई, विजेट के साइज़ में बदलाव करने और ज़्यादा सुविधा देने से जुड़ी सुविधाओं के बारे में बताया गया है. इसमें यह भी बताया गया है कि अपने विजेट का साइज़ कैसे तय करें.

विजेट के साइज़ और लेआउट के लिए बेहतर एपीआई का इस्तेमाल करना

Android 12 (एपीआई लेवल 31) से, साइज़ एट्रिब्यूट की बेहतर जानकारी दी जा सकती है. साथ ही, यहां दिए गए तरीके अपनाकर फ़्लेक्सिबल लेआउट बनाए जा सकते हैं. इनके बारे में यहां दिए गए सेक्शन में बताया गया है:

  1. विजेट के साइज़ से जुड़ी अन्य पाबंदियां तय करें.

  2. रिस्पॉन्सिव लेआउट या सटीक लेआउट उपलब्ध कराना.

Android के पिछले वर्शन में, OPTION_APPWIDGET_MIN_WIDTH, OPTION_APPWIDGET_MIN_HEIGHT, OPTION_APPWIDGET_MAX_WIDTH, और OPTION_APPWIDGET_MAX_HEIGHT एक्स्ट्रा का इस्तेमाल करके, किसी विजेट के साइज़ की रेंज पता की जा सकती है. इसके बाद, विजेट के साइज़ का अनुमान लगाया जा सकता है. हालांकि, यह तरीका हर स्थिति में काम नहीं करता. Android 12 या इसके बाद के वर्शन को टारगेट करने वाले विजेट के लिए, हमारा सुझाव है कि रिस्पॉन्सिव या सटीक लेआउट उपलब्ध कराएं.

विजेट के साइज़ से जुड़ी अतिरिक्त सीमाएं तय करना

Android 12 में ऐसे एपीआई जोड़े गए हैं जिनकी मदद से, यह पक्का किया जा सकता है कि आपका विजेट अलग-अलग स्क्रीन साइज़ वाले डिवाइसों पर ज़्यादा भरोसेमंद तरीके से काम करे.

मौजूदा minWidth, minHeight, minResizeWidth, और minResizeHeight एट्रिब्यूट के साथ-साथ, इन नए appwidget-provider एट्रिब्यूट का इस्तेमाल करें:

  • targetCellWidth और targetCellHeight: इनसे लॉन्चर ग्रिड सेल के हिसाब से, विजेट का टारगेट साइज़ तय किया जाता है. अगर इन्हें तय किया जाता है, तो minWidth या minHeight के बजाय इन एट्रिब्यूट का इस्तेमाल किया जाता है.

  • maxResizeWidth और maxResizeHeight: इनसे यह तय होता है कि लॉन्चर, उपयोगकर्ता को विजेट का साइज़ ज़्यादा से ज़्यादा कितना बदलने की अनुमति देता है.

यहां दिए गए एक्सएमएल में, साइज़िंग एट्रिब्यूट इस्तेमाल करने का तरीका बताया गया है.

<appwidget-provider
  ...
  android:targetCellWidth="3"
  android:targetCellHeight="2"
  android:maxResizeWidth="250dp"
  android:maxResizeHeight="110dp">
</appwidget-provider>

रिस्पॉन्सिव लेआउट उपलब्ध कराना

अगर विजेट के साइज़ के हिसाब से लेआउट में बदलाव करना है, तो हमारा सुझाव है कि लेआउट का एक छोटा सेट बनाएं. हर लेआउट, साइज़ की एक रेंज के लिए मान्य होता है. अगर ऐसा नहीं किया जा सकता, तो दूसरा विकल्प यह है कि इस पेज पर बताए गए तरीके के मुताबिक, रनटाइम में विजेट के सटीक साइज़ के आधार पर लेआउट उपलब्ध कराएं.

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

यहां दिए गए कोड के उदाहरण में, लेआउट की सूची देने का तरीका बताया गया है.

Kotlin

override fun onUpdate(...) {
    val smallView = ...
    val tallView = ...
    val wideView = ...

    val viewMapping: Map<SizeF, RemoteViews> = mapOf(
            SizeF(150f, 100f) to smallView,
            SizeF(150f, 200f) to tallView,
            SizeF(215f, 100f) to wideView
    )
    val remoteViews = RemoteViews(viewMapping)

    appWidgetManager.updateAppWidget(id, remoteViews)
}

Java

@Override
public void onUpdate(...) {
    RemoteViews smallView = ...;
    RemoteViews tallView = ...;
    RemoteViews wideView = ...;

    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    viewMapping.put(new SizeF(150f, 100f), smallView);
    viewMapping.put(new SizeF(150f, 200f), tallView);
    viewMapping.put(new SizeF(215f, 100f), wideView);
    RemoteViews remoteViews = new RemoteViews(viewMapping);

    appWidgetManager.updateAppWidget(id, remoteViews);
}

मान लें कि विजेट में ये एट्रिब्यूट हैं:

<appwidget-provider
    android:minResizeWidth="160dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="200dp">
</appwidget-provider>

ऊपर दिए गए कोड स्निपेट का मतलब यह है:

  • smallView 160 डीपी (minResizeWidth) × 110 डीपी (minResizeHeight) से लेकर 160 डीपी × 199 डीपी (अगला कटऑफ़ पॉइंट - 1 डीपी) तक के साइज़ के साथ काम करता है.
  • tallView 160dp × 200dp से लेकर 214dp (अगला कटऑफ़ पॉइंट - 1) × 200dp तक के साइज़ के साथ काम करता है.
  • wideView 215 डीपी × 110 डीपी (minResizeHeight) से लेकर 250 डीपी (maxResizeWidth) × 200 डीपी (maxResizeHeight) तक के डाइमेंशन के साथ काम करता है.

आपके विजेट को minResizeWidth × minResizeHeight से maxResizeWidth × maxResizeHeight तक के साइज़ रेंज के साथ काम करना चाहिए. इस रेंज में, लेआउट बदलने के लिए कटऑफ़ पॉइंट तय किया जा सकता है.

रिस्पॉन्सिव लेआउट का उदाहरण
पहली इमेज. रिस्पॉन्सिव लेआउट का उदाहरण.

सटीक लेआउट उपलब्ध कराना

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

इस समाधान को लागू करने के लिए, आपके ऐप्लिकेशन को यह तरीका अपनाना होगा:

  1. ओवरलोड AppWidgetProvider.onAppWidgetOptionsChanged(), जिसे साइज़ का सेट बदलने पर कॉल किया जाता है.

  2. AppWidgetManager.getAppWidgetOptions() को कॉल करें. इससे साइज़ वाली Bundle मिलती है.

  3. Bundle से AppWidgetManager.OPTION_APPWIDGET_SIZES कुंजी ऐक्सेस करें.

यहां दिए गए कोड के उदाहरण में, लेआउट की सटीक जानकारी देने का तरीका बताया गया है.

Kotlin

override fun onAppWidgetOptionsChanged(
        context: Context,
        appWidgetManager: AppWidgetManager,
        id: Int,
        newOptions: Bundle?
) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions)
    // Get the new sizes.
    val sizes = newOptions?.getParcelableArrayList<SizeF>(
            AppWidgetManager.OPTION_APPWIDGET_SIZES
    )
    // Check that the list of sizes is provided by the launcher.
    if (sizes.isNullOrEmpty()) {
        return
    }
    // Map the sizes to the RemoteViews that you want.
    val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews))
    appWidgetManager.updateAppWidget(id, remoteViews)
}

// Create the RemoteViews for the given size.
private fun createRemoteViews(size: SizeF): RemoteViews { }

Java

@Override
public void onAppWidgetOptionsChanged(
    Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
    // Get the new sizes.
    ArrayList<SizeF> sizes =
        newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES);
    // Check that the list of sizes is provided by the launcher.
    if (sizes == null || sizes.isEmpty()) {
      return;
    }
    // Map the sizes to the RemoteViews that you want.
    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    for (SizeF size : sizes) {
        viewMapping.put(size, createRemoteViews(size));
    }
    RemoteViews remoteViews = new RemoteViews(viewMapping);
    appWidgetManager.updateAppWidget(id, remoteViews);
}

// Create the RemoteViews for the given size.
private RemoteViews createRemoteViews(SizeF size) { }

अपने विजेट का साइज़ तय करना

Android 12 या उसके बाद के वर्शन पर काम करने वाले डिवाइसों के लिए, हर विजेट को targetCellWidth और targetCellHeight तय करना होगा. इसके अलावा, Android के सभी वर्शन के लिए minWidth और minHeight तय करना होगा. इससे यह पता चलेगा कि डिफ़ॉल्ट रूप से, विजेट कम से कम कितनी जगह लेता है. हालांकि, जब उपयोगकर्ता अपनी होम स्क्रीन पर कोई विजेट जोड़ते हैं, तो आम तौर पर यह आपकी तय की गई कम से कम चौड़ाई और लंबाई से ज़्यादा जगह लेता है.

Android की होम स्क्रीन पर, उपयोगकर्ताओं को उपलब्ध जगहों की एक ग्रिड दिखती है. इस पर वे विजेट और आइकॉन रख सकते हैं. यह ग्रिड, डिवाइस के हिसाब से अलग-अलग हो सकता है. उदाहरण के लिए, कई हैंडसेट में 5x4 ग्रिड होता है. वहीं, टैबलेट में बड़ा ग्रिड हो सकता है. जब आपका विजेट जोड़ा जाता है, तो उसे कम से कम उतनी सेल में फैलाया जाता है जितनी में वह हॉरिज़ॉन्टल और वर्टिकल तौर पर फ़िट हो सके. ऐसा Android 12 या इसके बाद के वर्शन वाले डिवाइसों पर, targetCellWidth और targetCellHeight की शर्तों को पूरा करने के लिए किया जाता है. इसके अलावा, Android 11 (एपीआई लेवल 30) या इससे पहले के वर्शन वाले डिवाइसों पर, minWidth और minHeight की शर्तों को पूरा करने के लिए भी ऐसा किया जाता है.

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

सेल की संख्या (चौड़ाई x ऊंचाई) पोर्ट्रेट मोड में उपलब्ध साइज़ (डीपी) लैंडस्केप मोड में उपलब्ध साइज़ (डीपी)
1x1 57x102dp 127x51dp
2x1 130x102dp 269x51dp
3x1 203x102dp 412x51dp
4x1 276x102dp 554x51dp
5x1 349x102dp 697x51dp
5x2 349x220dp 697x117dp
5x3 349x337dp 697x184dp
5x4 349x455dp 697x250dp
... ... ...
n x m (73n - 16) x (118m - 16) (142n - 15) x (66m - 15)

minWidth, minResizeWidth, और maxResizeWidth एट्रिब्यूट के लिए दी गई वैल्यू के बारे में बताने के लिए, पोर्ट्रेट मोड के सेल साइज़ का इस्तेमाल करें. इसी तरह, लैंडस्केप मोड में सेल के साइज़ का इस्तेमाल करके, minHeight, minResizeHeight, और maxResizeHeight एट्रिब्यूट के लिए दी गई वैल्यू के बारे में बताएं.

ऐसा इसलिए होता है, क्योंकि पोर्ट्रेट मोड में सेल की चौड़ाई, लैंडस्केप मोड की तुलना में कम होती है. इसी तरह, लैंडस्केप मोड में सेल की ऊंचाई, पोर्ट्रेट मोड की तुलना में कम होती है.

उदाहरण के लिए, अगर आपको Google Pixel 4 पर अपने विजेट की चौड़ाई को एक सेल तक कम करना है, तो आपको minResizeWidth को ज़्यादा से ज़्यादा 56dp पर सेट करना होगा. इससे यह पक्का किया जा सकेगा कि minResizeWidth एट्रिब्यूट की वैल्यू 57dp से कम है. ऐसा इसलिए, क्योंकि पोर्ट्रेट मोड में सेल की चौड़ाई कम से कम 57dp होती है. इसी तरह, अगर आपको एक ही डिवाइस पर एक सेल में अपने विजेट की ऊंचाई को बदलने की सुविधा चाहिए, तो आपको अपने minResizeHeight को ज़्यादा से ज़्यादा 50dp पर सेट करना होगा. इससे यह पक्का किया जा सकेगा कि minResizeHeight एट्रिब्यूट की वैल्यू 51dp से कम है. ऐसा इसलिए, क्योंकि लैंडस्केप मोड में एक सेल की ऊंचाई कम से कम 51dp होती है.

हर विजेट का साइज़, minResizeWidth/minResizeHeight और maxResizeWidth/maxResizeHeight एट्रिब्यूट के बीच की साइज़ रेंज के हिसाब से बदला जा सकता है. इसका मतलब है कि विजेट को इन दोनों एट्रिब्यूट के बीच की किसी भी साइज़ रेंज के हिसाब से अडजस्ट किया जा सकता है.

उदाहरण के लिए, प्लेसमेंट पर विजेट का डिफ़ॉल्ट साइज़ सेट करने के लिए, इन एट्रिब्यूट को सेट किया जा सकता है:

<appwidget-provider
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp">
</appwidget-provider>

इसका मतलब है कि विजेट का डिफ़ॉल्ट साइज़ 3x2 सेल है. यह targetCellWidth और targetCellHeight एट्रिब्यूट से तय होता है. Android 11 या इससे पहले के वर्शन वाले डिवाइसों के लिए, यह minWidth और minHeight एट्रिब्यूट से तय होता है. इसका साइज़ 180×110dp है. दूसरे मामले में, डिवाइस के हिसाब से सेल का साइज़ अलग-अलग हो सकता है.

इसके अलावा, अपने विजेट के लिए काम करने वाले साइज़ की रेंज सेट करने के लिए, इन एट्रिब्यूट को सेट किया जा सकता है:

<appwidget-provider
    android:minResizeWidth="180dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="530dp"
    android:maxResizeHeight="450dp">
</appwidget-provider>

ऊपर दिए गए एट्रिब्यूट के मुताबिक, विजेट की चौड़ाई को 180dp से 530dp तक और ऊंचाई को 110dp से 450dp तक बदला जा सकता है. इसके बाद, विजेट का साइज़ 3x2 से 5x2 सेल तक बदला जा सकता है. हालांकि, इसके लिए ये शर्तें पूरी होनी चाहिए:

Kotlin

val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small)
val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium)
val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large)

val viewMapping: Map<SizeF, RemoteViews> = mapOf(
        SizeF(180f, 110f) to smallView,
        SizeF(270f, 110f) to mediumView,
        SizeF(270f, 280f) to largeView
)

appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))

Java

RemoteViews smallView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small);
RemoteViews mediumView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium);
RemoteViews largeView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large);

Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
viewMapping.put(new SizeF(180f, 110f), smallView);
viewMapping.put(new SizeF(270f, 110f), mediumView);
viewMapping.put(new SizeF(270f, 280f), largeView);
RemoteViews remoteViews = new RemoteViews(viewMapping);

appWidgetManager.updateAppWidget(id, remoteViews);

मान लें कि विजेट, पहले दिए गए कोड स्निपेट में तय किए गए रिस्पॉन्सिव लेआउट का इस्तेमाल करता है. इसका मतलब है कि R.layout.widget_weather_forecast_small के तौर पर तय किया गया लेआउट, 180 डीपी (minResizeWidth) x 110 डीपी (minResizeHeight) से लेकर 269x279 डीपी (अगले कटऑफ़ पॉइंट - 1) तक इस्तेमाल किया जाता है. इसी तरह, R.layout.widget_weather_forecast_medium का इस्तेमाल 270x110dp से 270x279dp तक किया जाता है. वहीं, R.layout.widget_weather_forecast_large का इस्तेमाल 270x280dp से 530dp (maxResizeWidth) x 450dp (maxResizeHeight) तक किया जाता है.

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

सबसे छोटे 3x2-ग्रिड साइज़ में मौसम की जानकारी देने वाले विजेट का उदाहरण. यूज़र इंटरफ़ेस में, जगह का नाम (टोक्यो), तापमान (14°), और कुछ हद तक बादल छाए होने का निशान दिख रहा है.
दूसरी इमेज. 3x2 R.layout.widget_weather_forecast_small.

4x2 &#39;मीडियम&#39; साइज़ में मौसम की जानकारी देने वाले विजेट का उदाहरण. इस तरह से विजेट का साइज़ बदलने पर, विजेट के पिछले साइज़ का पूरा यूज़र इंटरफ़ेस (यूआई) दिखता है. साथ ही, इसमें &#39;ज़्यादातर बादल छाए रहेंगे&#39; लेबल और शाम 4 बजे से 7 बजे तक के तापमान का पूर्वानुमान दिखता है.
तीसरी इमेज. 4x2 R.layout.widget_weather_forecast_medium.

5x2 &#39;मीडियम&#39; साइज़ में मौसम की जानकारी देने वाले विजेट का उदाहरण. इस तरह से विजेट का साइज़ बदलने पर, आपको पहले जैसा यूज़र इंटरफ़ेस (यूआई) दिखेगा. हालांकि, इसमें एक सेल की लंबाई तक बदलाव किया गया है, ताकि यह ज़्यादा हॉरिज़ॉन्टल स्पेस ले सके.
चौथी इमेज. 5x2 R.layout.widget_weather_forecast_medium.

5x3 &#39;बड़ा&#39; साइज़ वाला मौसम का विजेट. विजेट का साइज़ बदलने पर
            यह पिछले विजेट के साइज़ के सभी यूज़र इंटरफ़ेस (यूआई) पर काम करता है.
            साथ ही, इसमें एक ऐसा व्यू जोड़ा जाता है जिसमें मंगलवार और बुधवार के मौसम का पूर्वानुमान होता है. धूप या बारिश के मौसम और हर दिन के लिए ज़्यादा और कम तापमान दिखाने वाले सिंबल.
पांचवीं इमेज. 5x3 R.layout.widget_weather_forecast_large.

5x4 &#39;बड़ा&#39; साइज़ में मौसम की जानकारी देने वाले विजेट का उदाहरण. इस तरह से विजेट का साइज़ बदलने पर, विजेट के पिछले साइज़ के सभी यूज़र इंटरफ़ेस (यूआई) दिखते हैं. साथ ही, इसमें गुरुवार और शुक्रवार (और उनके मिलते-जुलते सिंबल) भी दिखते हैं. इन सिंबल से, हर दिन के मौसम के साथ-साथ ज़्यादा से ज़्यादा और कम से कम तापमान के बारे में भी पता चलता है.
छठी इमेज. 5x4 R.layout.widget_weather_forecast_large.