提供彈性的小工具版面配置

本頁說明在調整小工具大小的方式,以及 Android 12 (API 級別 31) 中推出的更多彈性功能。以及如何決定小工具的大小

針對小工具大小和版面配置使用改良的 API

從 Android 12 (API 級別 31) 開始,您可以按照下列步驟提供更精細的大小屬性和彈性的版面配置,如後續章節所述:

  1. 指定其他小工具大小限制。

  2. 提供回應式版面配置確切版面配置

在舊版 Android 中,您可以使用 OPTION_APPWIDGET_MIN_WIDTHOPTION_APPWIDGET_MIN_HEIGHTOPTION_APPWIDGET_MAX_WIDTHOPTION_APPWIDGET_MAX_HEIGHT 額外擷取小工具大小範圍,然後預估小工具的大小,但這個邏輯並非在所有情況下都有效。針對指定 Android 12 以上版本的小工具,建議您提供回應式確切版面配置

指定其他小工具大小限制

Android 12 新增了 API,可確保在各種螢幕大小的不同裝置上,小工具的大小更穩定。

除了現有的 minWidthminHeightminResizeWidthminResizeHeight 屬性外,您也可以使用下列新的 appwidget-provider 屬性:

以下 XML 說明如何使用尺寸屬性。

<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 支援 160dp (minResizeWidth) × 110dp (minResizeHeight) 至 160dp × 199dp (下一個截止點 - 1dp)。
  • tallView 支援 160 × 200 dp 到 214 dp (下一個截止點 - 1) × 200 dp。
  • wideView 支援 215 dp × 110 dp (minResizeHeight) 至 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight)。

小工具必須支援 minResizeWidth × minResizeHeightmaxResizeWidth × maxResizeHeight 之間的大小範圍。在這個範圍內,您可以決定切換版面配置的截止點。

回應式版面配置範例
圖 1 回應式版面配置範例。

提供確切的版面配置

如果少數一組回應式版面配置不適用,您可以改為根據小工具顯示大小,提供不同的版面配置。如果是手機 (直向和橫向模式),通常有兩種尺寸,摺疊式裝置則為四種尺寸。

如要實作這項解決方案,應用程式必須執行下列步驟:

  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 以上版本的裝置 (或搭載 Android 12 以上版本的裝置) 定義 targetCellWidthtargetCellHeight,或為所有 Android 版本定義 minWidthminHeight,指出小工具 預設所消耗的最低空間量。不過,當使用者在主畫面中新增小工具時,其占用空間通常超過您指定的最小寬度和高度。

Android 主畫面提供一個可用空間格狀,讓使用者可以放進小工具和圖示。此格狀空間可能因裝置而異;例如,許多手機提供 5x4 方格,而平板電腦則可提供更大的格狀版面。新增小工具時,該小工具會延伸至水平和垂直佔用的儲存格數量下限,以滿足targetCellWidthtargetCellHeight在搭載 Android 12 以上版本的裝置上,或minWidthminHeight10 或 Android 3 以下級別的裝置。1

儲存格的寬度和高度,以及小工具套用的自動邊界大小可能會因裝置而異。請使用下表,根據您想要的已涵蓋網格儲存格數量,大致評估小工具在一般 5x4 格狀手機中的最小尺寸:

儲存格數量 (寬 x 高) 直向模式下的可用大小 (dp) 橫向模式的可用大小 (dp)
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 (118 公尺 - 16) (142n - 15) x (66 公尺 - 15)

請使用直向模式儲存格大小,做為您為 minWidthminResizeWidthmaxResizeWidth 屬性提供的值。同樣地,您也可以使用橫向模式儲存格大小,告知您為 minHeightminResizeHeightmaxResizeHeight 屬性提供的值。

原因在於,直向模式下的儲存格寬度通常比橫向模式下的儲存格寬度小。此外,在橫向模式中,儲存格高度通常比直向模式下的儲存格高度還要小。

舉例來說,如要將小工具寬度調整為 Google Pixel 4 上一個儲存格的大小,您必須將 minResizeWidth 設為最多 56dp,確保 minResizeWidth 屬性的值小於 57dp,因為直向儲存格的寬度至少為 57dp。同樣地,如果您希望小工具高度可在同一裝置的一個儲存格中調整大小,必須將 minResizeHeight 設為最多 50dp,確保 minResizeHeight 屬性的值小於 51dp,因為在橫向模式下,一個儲存格的高度至少為 51dp。

每個小工具都可以在 minResizeWidth/minResizeHeightmaxResizeWidth/maxResizeHeight 屬性之間的大小範圍內調整大小,這表示必須根據小工具之間的任何大小範圍進行調整。

舉例來說,您可以設定下列屬性,為刊登位置設定刊登位置的預設大小:

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

也就是說,如果裝置搭載的是 targetCellWidthtargetCellHeight 屬性,則小工具的預設大小為 3x2 儲存格,或 180×110dp (由 minWidthminHeight 指定,適用於搭載 Android 11 以下版本的裝置)。在第二種情況中,儲存格的大小可能會因裝置而異。

此外,如要設定支援的小工具大小範圍,可以設定下列屬性:

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

根據上述屬性的指定,小工具的寬度可調整為 180dp 到 530dp,高度可調整至 110dp 到 450dp。如此一來,只要符合下列條件,這個小工具便可從 3x2 到 5x2 儲存格調整大小:

  • 裝置採用 5x4 格線。
  • 儲存格數量與可用大小之間的對應關係 (以 dp 為單位) 會遵循本頁的顯示最小尺寸估計值表格
  • 小工具會根據該尺寸範圍自動調整。

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 dp (minResizeWidth) x 110dp (minResizeHeight) 到 269x279dp (下一個截止點 - 1)。同樣地,R.layout.widget_weather_forecast_medium 的使用範圍是從 270x110dp 到 270x279dp,而 R.layout.widget_weather_forecast_large 則使用從 270x280dp 到 530dp (maxResizeWidth) x 450dp (maxResizeHeight)。

當使用者調整小工具的大小時,小工具的外觀會配合儲存格中的各種大小而改變,如以下範例所示。

最小 3x2 格狀空間的天氣小工具範例。UI 會顯示地點名稱 (東京)、溫度 (14°),以及表示局部多雲的符號。
圖 2. 3x2 R.layout.widget_weather_forecast_small

4x2「中」大小的天氣小工具範例。以這種方式調整小工具大小時,系統會沿用先前小工具大小的所有 UI 大小,新增「大部分的多雲」標籤,並提供下午 4 點到晚上 7 點的溫度預測。
圖 3 4x2 R.layout.widget_weather_forecast_medium

天氣小工具範例,大小為 5x2「中」。以這種方式調整小工具大小後,使用者介面會與前一個大小的大小相同,但它延展一個儲存格的長度,以佔據更多水平空間。
圖 4:5x2 R.layout.widget_weather_forecast_medium

天氣小工具範例,大小為 5x3「大」。這樣就能根據先前小工具大小的所有 UI 調整小工具大小,並在小工具中新增檢視畫面,提供週二和週三的天氣預報。符號表示每天晴朗或多雨的天氣,以及高溫和低溫。
圖 5 5x3 R.layout.widget_weather_forecast_large

天氣小工具範例 (大小為 5x4)。以這種方式調整小工具大小時,系統會採用先前小工具大小的所有 UI,並新增週四和週五 (及其對應的符號,用於表示天氣類型,以及每天的高低溫)。
圖 6:5 x 4 R.layout.widget_weather_forecast_large