Flexible Widget-Layouts bereitstellen

Auf dieser Seite werden Optimierungen für die Widget-Größe und mehr Flexibilität beschrieben, die in Android 12 (API-Level 31) eingeführt wurden. Außerdem wird beschrieben, wie Sie die Größe für Ihr Widget bestimmen.

Verbesserte APIs für Widget-Größen und -Layouts verwenden

Ab Android 12 (API-Level 31) kannst du detailliertere Größenattribute und flexible Layouts angeben. Gehe dazu wie in den folgenden Abschnitten beschrieben vor:

  1. Zusätzliche Größenbeschränkungen für Widgets angeben.

  2. Bereitstellung von responsiven Layouts oder exakten Layouts

In früheren Android-Versionen war es möglich, die Größenbereiche eines Widgets mithilfe der Extras OPTION_APPWIDGET_MIN_WIDTH, OPTION_APPWIDGET_MIN_HEIGHT, OPTION_APPWIDGET_MAX_WIDTH und OPTION_APPWIDGET_MAX_HEIGHT abzurufen und dann die Größe des Widgets zu schätzen. Diese Logik funktioniert jedoch nicht in allen Situationen. Für Widgets, die für Android 12 oder höher bestimmt sind, empfehlen wir responsive oder exakte Layouts.

Zusätzliche Einschränkungen für die Widget-Größe angeben

Unter Android 12 werden APIs hinzugefügt, mit denen du dafür sorgen kannst, dass die Größe deines Widgets auf verschiedenen Geräten mit unterschiedlichen Bildschirmgrößen zuverlässiger wird.

Verwenden Sie zusätzlich zu den vorhandenen Attributen minWidth, minHeight, minResizeWidth und minResizeHeight die folgenden neuen appwidget-provider-Attribute:

  • targetCellWidth und targetCellHeight: Definieren Sie die Zielgröße des Widgets in Bezug auf die Zellen des Launcher-Rasters. Wenn definiert, werden diese Attribute anstelle von minWidth oder minHeight verwendet.

  • maxResizeWidth und maxResizeHeight: Definiere die maximale Größe, auf die der Nutzer die Größe des Widgets im Launcher anpassen kann.

Der folgende XML-Code zeigt, wie die Größenattribute verwendet werden.

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

Responsive Layouts bereitstellen

Wenn sich das Layout je nach Größe des Widgets ändern muss, empfehlen wir, einen kleinen Satz von Layouts zu erstellen, die jeweils für einen Größenbereich gültig sind. Sollte dies nicht möglich sein, können Sie auch Layouts basierend auf der genauen Widgetgröße zur Laufzeit bereitstellen, wie auf dieser Seite beschrieben.

Diese Funktion ermöglicht eine reibungslosere Skalierung und einen insgesamt besseren Systemzustand, da die App nicht jedes Mal neu gestartet werden muss, wenn das Widget in einer anderen Größe angezeigt wird.

Das folgende Codebeispiel zeigt, wie Sie eine Liste von Layouts bereitstellen.

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);
}

Angenommen, das Widget hat die folgenden Attribute:

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

Das vorherige Code-Snippet bedeutet Folgendes:

  • smallView wird von 160 dp (minResizeWidth) × 110 dp (minResizeHeight) bis 160 dp × 199 dp (nächster Sperrpunkt – 1 dp) unterstützt.
  • tallView wird von 160 dp × 200 dp bis 214 dp (nächster Grenzpunkt – 1) × 200 dp unterstützt.
  • wideView unterstützt 215 dp × 110 dp (minResizeHeight) bis 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight).

Das Widget muss den Größenbereich von minResizeWidth × minResizeHeight bis maxResizeWidth × maxResizeHeight unterstützen. Innerhalb dieses Bereichs können Sie den Grenzwert für den Layoutwechsel festlegen.

Beispiel für ein responsives Layout
Abbildung 1. Beispiel für ein responsives Layout.

Genaue Layouts bereitstellen

Wenn eine kleine Anzahl responsiver Layouts nicht möglich ist, können Sie stattdessen verschiedene Layouts bereitstellen, die auf die Größen zugeschnitten sind, in denen das Widget angezeigt wird. In der Regel sind dies zwei Größen für Smartphones (Hoch- und Querformat) und vier Größen für faltbare Smartphones.

Zur Implementierung dieser Lösung muss Ihre Anwendung die folgenden Schritte ausführen:

  1. Die Überlastung AppWidgetProvider.onAppWidgetOptionsChanged() wird aufgerufen, wenn sich die Größen ändern.

  2. Rufen Sie AppWidgetManager.getAppWidgetOptions() auf, das ein Bundle-Objekt mit den Größen zurückgibt.

  3. Greifen Sie von Bundle auf den AppWidgetManager.OPTION_APPWIDGET_SIZES-Schlüssel zu.

Das folgende Codebeispiel zeigt, wie genaue Layouts bereitgestellt werden.

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) { }

Größe für das Widget bestimmen

In jedem Widget muss für Geräte mit Android 12 oder höher ein targetCellWidth und ein targetCellHeight definiert werden. Für alle Android-Versionen müssen minWidth und minHeight angegeben werden. Diese geben den standardmäßigen Mindestspeicherplatz an. Wenn Nutzer jedoch ihrem Startbildschirm ein Widget hinzufügen, belegt es in der Regel mehr als die von Ihnen angegebene Mindestbreite und -höhe.

Android-Startbildschirme bieten Nutzern ein Raster mit verfügbaren Bereichen, in denen sie Widgets und Symbole platzieren können. Dieses Raster kann je nach Gerät variieren. Viele Smartphones haben beispielsweise ein 5x4-Raster und Tablets bieten ein größeres Raster. Wenn das Widget hinzugefügt wird, wird es so gestreckt, dass es die Mindestanzahl horizontaler und vertikaler Zellen einnimmt, die erforderlich ist, um die Einschränkungen für targetCellWidth und targetCellHeight auf Geräten mit Android 12 oder höher bzw. die Einschränkungen minWidth und minHeight auf Geräten mit Android 11 (API-Level 30) oder niedriger zu erfüllen.

Sowohl die Breite und Höhe einer Zelle als auch die Größe der automatischen Ränder, die auf Widgets angewendet werden, können je nach Gerät variieren. Anhand der folgenden Tabelle können Sie die Mindestabmessungen Ihres Widgets in einem typischen 5x4-Raster-Mobilgerät anhand der gewünschten Anzahl besetzter Rasterzellen schätzen:

Anzahl der Zellen (Breite x Höhe) Verfügbare Größe im Hochformat (dp) Verfügbare Größe im Querformat (dp)
1 × 1 57 × 102 dp 127 × 51 dp
2 × 1 130 × 102 dp 269 × 51 dp
3 × 1 203 × 102 dp 412 × 51 dp
4x1 276 × 102 dp 554 × 51 dp
5x1 349 × 102 dp 697 × 51 dp
5x2 349 × 220 dp 697 × 117 dp
5x3 349 × 337 dp 697 × 184 dp
5x4 349 × 455 dp 697 × 250 dp
n x m (73n–16) x (118–16) (142n–15) x (66–15)

Verwenden Sie die Zellengrößen im Hochformat, um die Werte für die Attribute minWidth, minResizeWidth und maxResizeWidth festzulegen. Verwenden Sie auf ähnliche Weise die Zellengrößen im Querformat, um die Werte für die Attribute minHeight, minResizeHeight und maxResizeHeight festzulegen.

Der Grund dafür ist, dass die Zellenbreite im Hochformat normalerweise kleiner als im Querformat ist. Entsprechend ist die Zellenhöhe im Querformat normalerweise kleiner als im Hochformat.

Wenn Sie beispielsweise möchten, dass die Breite des Widgets auf einem Google Pixel 4 bis auf eine Zelle verkleinert werden kann, müssen Sie minResizeWidth auf maximal 56 dp festlegen, damit der Wert für das Attribut minResizeWidth kleiner als 57 dp ist, da eine Zelle im Hochformat mindestens 57 dp breit ist. Wenn Sie möchten, dass die Höhe Ihres Widgets in einer Zelle auf demselben Gerät angepasst werden kann, müssen Sie minResizeHeight auf maximal 50 dp festlegen, damit der Wert für das Attribut minResizeHeight kleiner als 51 dp ist, da eine Zelle im Querformat mindestens 51 dp hoch ist.

Die Größe jedes Widgets kann innerhalb der Größenbereiche zwischen den Attributen minResizeWidth/minResizeHeight und maxResizeWidth/maxResizeHeight angepasst werden. Das bedeutet, dass es an alle Größenbereiche angepasst werden muss.

Um beispielsweise die Standardgröße des Widgets für die Platzierung festzulegen, können Sie die folgenden Attribute festlegen:

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

Das bedeutet, dass die Standardgröße des Widgets 3 x 2 Zellen beträgt, wie in den Attributen targetCellWidth und targetCellHeight angegeben, oder 180 × 110 dp, wie von minWidth und minHeight für Geräte mit Android 11 oder niedriger angegeben. In letzterem Fall kann die Größe der Zellen je nach Gerät variieren.

Mit den folgenden Attributen können Sie außerdem die unterstützten Größenbereiche Ihres Widgets festlegen:

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

Wie in den vorherigen Attributen angegeben, kann die Breite des Widgets von 180 dp bis 530 dp und die Höhe zwischen 110 dp und 450 dp geändert werden. Die Größe des Widgets kann dann von 3 x 2 auf 5 x 2 Zellen geändert werden, wenn die folgenden Bedingungen erfüllt sind:

  • Das Gerät verfügt über ein 5x4-Raster.
  • Die Zuordnung zwischen der Anzahl der Zellen und der verfügbaren Größe in dps folgt der Tabelle mit der Schätzung der Mindestabmessungen auf dieser Seite.
  • Das Widget passt sich an diesen Größenbereich an.

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

Angenommen, das Widget verwendet die in den vorherigen Code-Snippets definierten responsiven Layouts. Das bedeutet, dass das als R.layout.widget_weather_forecast_small angegebene Layout von 180 dp (minResizeWidth) × 110 dp (minResizeHeight) bis 269 × 279 dp (nächste Grenzpunkte – 1) verwendet wird. In ähnlicher Weise wird R.layout.widget_weather_forecast_medium von 270 × 110 dp bis 270 × 279 dp und R.layout.widget_weather_forecast_large von 270 × 280 dp bis 530 dp (maxResizeWidth) × 450 dp (maxResizeHeight) verwendet.

Wenn der Nutzer die Größe des Widgets ändert, ändert sich seine Darstellung und passt sich wie in den folgenden Beispielen an die Größe in den Zellen an.

Beispiel für ein Wetter-Widget in der kleinsten 3x2-Rastergröße. Die Benutzeroberfläche zeigt den Standortnamen (Tokio), die Temperatur (14°) und das Symbol für teilweise bewölktes Wetter an.
Abbildung 2. 3x2 R.layout.widget_weather_forecast_small.

Beispiel für ein Wetter-Widget in einer mittelgroßen Größe 4 x 2 Die Größe des Widgets auf diese Weise baut auf der gesamten Benutzeroberfläche der vorherigen Widget-Größe auf. Außerdem wird das Label „Überwiegend bewölkt“ und eine Temperaturprognose von 16:00 bis 19:00 Uhr hinzugefügt.
Abbildung 3. 4 × 2 R.layout.widget_weather_forecast_medium.

Beispiel für ein Wetter-Widget in einer mittelgroßen Größe 5x2 Wenn Sie die Größe des Widgets auf diese Weise ändern, hat dies die gleiche Benutzeroberfläche wie die vorherige Größe, mit der Ausnahme, dass das Widget um eine Zelle gestreckt wird, um mehr horizontalen Platz einzunehmen.
Abbildung 4. 5 × 2 R.layout.widget_weather_forecast_medium.

Beispiel für ein Wetter-Widget in einer Größe von 5 x 3. Wenn Sie die Größe des Widgets auf diese Weise anpassen, baut sie auf der gesamten UI aus den vorherigen Widget-Größen auf und fügt im Widget eine Ansicht mit einer Wetterprognose für Dienstag und Mittwoch hinzu. Symbole für sonniges oder regnerisches Wetter sowie Höchst- und Tiefsttemperaturen für den jeweiligen Tag.
Abbildung 5. 5x3 R.layout.widget_weather_forecast_large.

Beispiel für ein Wetter-Widget in einer Größe 5x4 (groß). Wenn Sie die Größe des Widgets auf diese Weise anpassen, baut es auf der gesamten UI aus den vorherigen Widget-Größen auf und fügt Donnerstag und Freitag sowie die entsprechenden Symbole hinzu, die die Art des Wetters sowie die Höchst- und Tiefsttemperaturen für jeden Tag angeben.
Abbildung 6. 5 × 4 R.layout.widget_weather_forecast_large.