如何在同一个应用程序中添加多个小部件?

67

我刚刚完成了我的Android小部件。现在我需要为用户提供不同大小的小部件进行选择。

例如,我需要中、小、大三种不同尺寸的小部件,因此当用户安装应用程序并按住主屏幕选择小部件时,在小部件菜单中我希望他看到三个带有相同应用程序名称但大小不同的小部件。像这样:

helloSmall helloMedium helloLarge

我已经准备好了中等大小的小部件,但是如何在同一个应用程序中添加小和大的呢?请注意,所有三个尺寸都包含完全相同的数据和操作,只是大小和背景不同。

5个回答

104

你需要在清单文件中为每种类型定义一个接收器,例如:

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

这将使您能够使用相同的AppWidgetProvider类用于多个小部件,在<appwidget-provider> XML中定义不同的小部件名称和大小。

如果您需要比<appwidget-provider> XML中更多的小部件差异,我会创建一个基本小部件类,实现所有不同类型之间的公共行为:

public abstract class MyBaseWidget extends AppWidgetProvider

然后你的每个具体实现都可以扩展 MyBaseWidget。然后在你的清单文件中,你将为每个具体实现定义一个接收器,例如:

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

7
谢谢您的回复。但是看起来我不能共享相同的小部件提供程序(如果这样做,只会显示清单中的第一个)。因此,基本上,对于我来说,多个小部件提供程序将是答案。是否有人正在使用一个小部件提供程序? - xandy
29
是的,我只是按照上面的指示操作,发现只有在指定不同的小部件提供程序类时才能正常工作。无论如何,非常感谢大家! :) - dimsuz
4
我也一样,需要多个小部件提供程序类来显示小部件。 - chakrit
1
我无法使用相同的AppWidgetProvider类,因为我不知道如何以编程方式获取布局,即在构建视图的AppWidgetProvider中有以下代码:RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);请注意“R.layout.widget”,这个值将根据清单文件中的<receiver>而异。是否有一种方法可以从AppWidgetProvider类以编程方式获取小部件提供程序中定义的布局?如果没有,那么子类化是我们唯一剩下的选项,以使用具有不同布局的相同AppWidgetProvider类。 - The Awnry Bear
1
@TheAwnryBear 是的,你可以使用 AppWidgetProviderInfo。这样你就可以像这样获取布局:AppWidgetProviderInfo.initialLayout。一个例子可能是:AppWidgetProviderInfo appInfo = appWidgetManager.getAppWidgetInfo(widgetId); appInfo.initialLayout; - HGPB
我们需要为第二个小部件创建一个单独的Java类文件吗? - Si8

28

实际上,每个小部件的android:name必须不同。如果您像示例中那样做,只有一个小部件会在小部件列表中可见。


根据@jblz的回答(澄清) - Richard Le Mesurier
1
是的!这就是问题所在!我最终创建了另一个小部件提供程序类,它只是扩展了第一个类,然后在清单中为两个小部件设置了这些类。 - Mārtiņš Briedis

11

大家好,我也遇到了同样的问题。

你需要实际上再添加第二个小部件提供程序;

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

享受


2
我们还需要一个单独的Java类文件来处理第二个小部件吗? - Si8

5

好的,基本上你需要:

为每个小部件创建布局文件。例如:main_small.xml,main_medium.xml ...

在xml目录中为每个小部件添加提供程序。例如:small_provider.xml,medium_provider.xml ...等等(注意,如果您没有xml目录,请将其添加到drawable目录下)。

现在怎么办!

  • 在清单中为每个小部件定义接收器。(就像主答案中的示例一样)

  • 您可以使用相同的布局或不同的布局。基本上这取决于您。

  • 在提供程序中,您应该有类似于这样的内容:

<?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"
    />

确保为每个提供程序指定您想要使用的目标布局文件。在此代码中,我正在请求布局目录中的main.xml文件。例如,对于我的中型小部件,我将有另一个具有完全相同代码的提供程序,但我将更改最后一行。

请注意,不要删除任何HTML标签。

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

如果这不够清楚,请告诉我,我可以在我的网站上上传一个可用的示例,您可以更仔细地查看它。请让我知道进展如何。

祝你好运。


2

其他答案中还有一些额外的信息...

  • 如果您正在复制提到的文件,并且您的小部件使用 Service 来提供某些功能,则可能需要复制您的服务。

  • 如果您复制了您的 Service请记得在清单文件中更新新的服务,否则新的服务将无法运行...

这浪费了我的一些时间。


如果您使用任何 BroadcastReceiver 发送 Intent 到您的重复 Service... 不要忘记更新该代码:

  • 现在,您必须向每个服务发送意图。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接