67

I've just finished my Android widget. Now I need to have different sizes of this widget for the user to choose from.

For example, I need a medium, small and large size widget, so when the user installs the app and hold the home screen then choose widget, in the widget menu I want him to see three widgets with the same app name but with the size. Something like this:

helloSmall helloMedium helloLarge

I have the medium one ready, but how can I add the small and the large in the same app? Knowing that all three sizes contain the same exact data and actions, just the size and the background are different.

Adinia
  • 3,722
  • 5
  • 40
  • 58
BarcaDroid
  • 673
  • 1
  • 6
  • 5

5 Answers5

103

You need a receiver definition for each type in your manifest file like:

    <receiver android:name=".MyWidget" android:label="@string/medium_widget_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/medium_widget_provider" />
    </receiver>

    <receiver android:name=".MyWidget" android:label="@string/large_widget_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/large_widget_provider" />
    </receiver>

This would allow you to have the same AppWidgetProvider class be used for multiple widgets, with different widget names and different sizes defined in the <appwidget-provider> XML.

Now if you need more differences in your widgets than what is in the <appwidget-provider> XML I would create a base widget class that implements all the common behavoir between the different types:

public abstract class MyBaseWidget extends AppWidgetProvider

And then each of your concrete implementations could extend MyBaseWidget. Then in your manifest file you would have a receiver definition for each of your concrete implementations like:

    <receiver android:name=".MyMediumWidget" android:label="@string/medium_widget_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/medium_widget_provider" />
    </receiver>

    <receiver android:name=".MyLargeWidget" android:label="@string/large_widget_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/large_widget_provider" />
    </receiver>
Mark B
  • 183,023
  • 24
  • 297
  • 295
  • 6
    Hi, thanks for your answer. But it seems that I cannot share the same widget provider. (if I do, only first in manifest is shown). So, basically, multiple widget providers would be the answer for me. Is anyone working with one widget provider? – xandy Jun 03 '10 at 07:26
  • 28
    Yep, just followed above instructions and found it only works if i specify different widget provider classes. Good anyway, thanks everyone! :) – dimsuz Aug 28 '10 at 17:53
  • 4
    Same here, need multiple widget provider classes for widgets to show up. – chakrit Sep 16 '10 at 16:20
  • I wasn't able to use the same AppWidgetProvider class because I don't know how to get the layout programmatically, i.e. I have this in my AppWidgetProvider where it builds the view: RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget); Notice the "R.layout.widget", this value will be different depending on which in the manifest. Is there a way to programmatically get the layout defined in the widget provider from the AppWidgetProvider class? If not, subclassing is the only option we have left to use the same AppWidgetProvider class with different layouts. – The Awnry Bear Feb 11 '13 at 01:25
  • 1
    @TheAwnryBear Yes, you use `AppWidgetProviderInfo`. This way you can get the layout like this: `AppWidgetProviderInfo.initialLayout`. An example might be: `AppWidgetProviderInfo appInfo = appWidgetManager.getAppWidgetInfo(widgetId); appInfo.initialLayout;` – HGPB May 01 '13 at 17:14
  • We need a separate Java class file for the second widget as well? – Si8 Sep 30 '13 at 12:38
27

Actually, android:name for each widget have to be different. If you will do this as in example, only one widget will be visible in widgets list.

korro
  • 499
  • 9
  • 17
11

Guys, I had the same problem.

You need to actually add a second widget provider aswell;

<receiver android:name=**".MyWidget**" android:label="@string/medium_widget_name">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
        android:resource="@xml/medium_widget_provider" />
</receiver>

<receiver android:name=**".MyWidget2"** android:label="@string/large_widget_name">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
        android:resource="@xml/large_widget_provider" />
</receiver>

Enjoy

jblz
  • 121
  • 1
  • 5
5

Ok so basically you will need:

layout file fore each widget. ex: main_small.xml, main_medium.xml ...

in the xml directory add a provider for each widget. ex: small_provider.xml, medium_provider.xml ... and so on (note if you don't have an xml directory add it under the drawable directory).

now what!

  • define a receiver in the manifest for each widget. (just like the example in the main answer)

  • you can use the same layout or deferent layout. basically this is up to you.

  • in your provider you should have something like this:

<?xml version="1.0" encoding="utf-8"?>

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip"
    android:minHeight="138dip"
    android:updatePeriodMillis="10000"
    android:initialLayout="@layout/main"
    />

make sure, for each provider to specify the target layout file you want to use. in this code I'm asking for the file main.xml in the layout directory. for my medium widget for example i'll have another provider with the same exact code but i'll change the last line

> android:initialLayout="@layout/medium".

I hope this helps if not let me know and I can upload a working example on my website and you can take a closer look at it. please let me know how it goes.

best of luck.

user308238
  • 51
  • 2
2

Some extra info to the other answers...

  • If you are duplicating the files mentioned, and if your widget uses a Service to provide some functionality, you might have to duplicate your service.

  • If you duplicate your Service, remember to update your manifest with the new service, otherwise the new service won't run...

This wasted some time for me.


If you use any BroadcastReceiver to send Intents to your duplicate Services... don't forget to update that code too:

  • you must now send intents to each of the services.
Richard Le Mesurier
  • 29,432
  • 22
  • 140
  • 255