Questa pagina descrive i perfezionamenti per il dimensionamento dei widget e la maggiore flessibilità introdotta in Android 12 (livello API 31). Descrive anche come determinare le dimensioni di un widget.
Utilizzare le API migliorate per le dimensioni e i layout dei widget
A partire da Android 12 (livello API 31), puoi fornire attributi di dimensioni più precisi e layout flessibili procedendo come descritto nelle sezioni seguenti:
Fornisci layout adattabili o layout esatti.
Nelle versioni precedenti di Android, è possibile ottenere gli intervalli di dimensioni di un
widget utilizzando gli
OPTION_APPWIDGET_MIN_WIDTH,
OPTION_APPWIDGET_MIN_HEIGHT,
OPTION_APPWIDGET_MAX_WIDTH,
e OPTION_APPWIDGET_MAX_HEIGHT
extra e poi stimare le dimensioni del widget, ma questa logica non funziona in tutte le
situazioni. Per i widget destinati ad Android 12 o versioni successive, consigliamo di fornire
layout adattabili o esatti.
Specificare vincoli di dimensionamento dei widget aggiuntivi
Android 12 aggiunge API che ti consentono di assicurarti che le dimensioni del widget siano più affidabili su diversi dispositivi con dimensioni dello schermo variabili.
Oltre agli attributi minWidth,
minHeight,
minResizeWidth,
e minResizeHeight
esistenti, utilizza i seguenti nuovi attributi appwidget-provider:
targetCellWidthetargetCellHeight: definiscono le dimensioni target del widget in termini di celle della griglia del launcher. Se definiti, questi attributi vengono utilizzati al posto diminWidthominHeight.maxResizeWidthemaxResizeHeight: definiscono le dimensioni massime a cui il launcher consente all'utente di ridimensionare il widget.
Il seguente XML mostra come utilizzare gli attributi di dimensionamento.
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
Fornire layout adattabili
Se il layout deve cambiare in base alle dimensioni del widget, ti consigliamo di creare un piccolo insieme di layout, ognuno valido per un intervallo di dimensioni. Se non è possibile, un'altra opzione è fornire layout basati sulle dimensioni esatte del widget in fase di runtime, come descritto in questa pagina.
Questa funzionalità consente una scalabilità più fluida e una migliore integrità complessiva del sistema, perché il sistema non deve riattivare l'app ogni volta che visualizza il widget in dimensioni diverse.
Il seguente esempio di codice mostra come fornire un elenco di layout.
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); }
Supponiamo che il widget abbia i seguenti attributi:
<appwidget-provider
android:minResizeWidth="160dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="250dp"
android:maxResizeHeight="200dp">
</appwidget-provider>
Il precedente snippet di codice significa quanto segue:
smallViewsupporta da 160 dp (minResizeWidth) × 110 dp (minResizeHeight) a 160 dp × 199 dp (punto di interruzione successivo - 1 dp).tallViewsupporta da 160 dp × 200 dp a 214 dp (punto di interruzione successivo - 1) × 200 dp.wideViewsupporta da 215 dp × 110 dp (minResizeHeight) a 250 dp (maxResizeWidth) × 200 dp (maxResizeHeight).
Il widget deve supportare l'intervallo di dimensioni da minResizeWidth × minResizeHeight a maxResizeWidth × maxResizeHeight. All'interno di questo intervallo, puoi decidere il punto di interruzione per cambiare layout.
Fornire layout esatti
Se un piccolo insieme di layout adattabili non è fattibile, puoi invece fornire layout diversi personalizzati in base alle dimensioni in cui viene visualizzato il widget. In genere si tratta di due dimensioni per gli smartphone (modalità Ritratto e Orizzontale) e quattro dimensioni per i dispositivi pieghevoli.
Per implementare questa soluzione, l'app deve eseguire i seguenti passaggi:
Esegui l'overload di
AppWidgetProvider.onAppWidgetOptionsChanged(), che viene chiamato quando cambia l'insieme delle dimensioni.Chiama
AppWidgetManager.getAppWidgetOptions(), che restituisce unBundlecontenente le dimensioni.Accedi alla chiave
AppWidgetManager.OPTION_APPWIDGET_SIZESdalBundle.
Il seguente esempio di codice mostra come fornire layout esatti.
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) { }
Determinare le dimensioni di un widget
Ogni widget deve definire targetCellWidth e targetCellHeight per i dispositivi con Android 12 o versioni successive oppure minWidth e minHeight per tutte le versioni di Android, indicando la quantità minima di spazio che occupa per impostazione predefinita. Tuttavia, quando gli utenti aggiungono un widget alla schermata Home, in genere occupa più della larghezza e dell'altezza minime specificate.
Le schermate Home di Android offrono agli utenti una griglia di spazi disponibili in cui possono inserire widget e icone. Questa griglia può variare in base al dispositivo; ad esempio, molti smartphone offrono una griglia 5x4 e i tablet possono offrire una griglia più grande. Quando viene aggiunto il widget, viene esteso per occupare il numero minimo di celle, orizzontalmente e verticalmente, necessario per soddisfare i vincoli di targetCellWidth e targetCellHeight sui dispositivi con Android 12 o versioni successive oppure i vincoli di minWidth e minHeight sui dispositivi con Android 11 (livello API 30) o versioni precedenti.
Sia la larghezza che l'altezza di una cella e le dimensioni dei margini automatici applicati ai widget possono variare a seconda del dispositivo. Utilizza la seguente tabella per stimare approssimativamente le dimensioni minime del widget in uno smartphone con griglia 5x4 tipica, in base al numero di celle della griglia occupate che vuoi:
| Numero di celle (larghezza x altezza) | Dimensioni disponibili in modalità Ritratto (dp) | Dimensioni disponibili in modalità Orizzontale (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 (118m - 16) | (142n - 15) x (66m - 15) |
Utilizza le dimensioni delle celle in modalità Ritratto per informare i valori forniti per gli attributi minWidth, minResizeWidth e maxResizeWidth. Allo stesso modo, utilizza le dimensioni delle celle in modalità Orizzontale per informare i valori forniti per gli attributi minHeight, minResizeHeight e maxResizeHeight.
Il motivo è che la larghezza della cella è in genere inferiore in modalità Ritratto rispetto alla modalità Orizzontale e, analogamente, l'altezza della cella è in genere inferiore in modalità Orizzontale rispetto alla modalità Ritratto.
Ad esempio, se vuoi che la larghezza del widget sia ridimensionabile fino a una cella su un Google Pixel 4, devi impostare minResizeWidth su un valore massimo di 56 dp per assicurarti che il valore dell'attributo minResizeWidth sia inferiore a 57 dp, perché una cella ha una larghezza di almeno 57 dp in modalità Ritratto.
Allo stesso modo, se vuoi che l'altezza del widget sia ridimensionabile in una cella sullo stesso dispositivo, devi impostare minResizeHeight su un valore massimo di 50 dp per assicurarti che il valore dell'attributo minResizeHeight sia inferiore a 51 dp, perché una cella ha un'altezza di almeno 51 dp in modalità Orizzontale.
Ogni widget è ridimensionabile all'interno degli intervalli di dimensioni tra gli attributi minResizeWidth/minResizeHeight e maxResizeWidth/maxResizeHeight, il che significa che deve adattarsi a qualsiasi intervallo di dimensioni tra questi attributi.
Ad esempio, per impostare le dimensioni predefinite del widget al momento del posizionamento, puoi impostare i seguenti attributi:
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
Ciò significa che le dimensioni predefinite del widget sono 3x2 celle, come specificato dagli attributi targetCellWidth e targetCellHeight, oppure 180×110 dp, come specificato da minWidth e minHeight per i dispositivi con Android 11 o versioni precedenti. In quest'ultimo caso, le dimensioni in celle possono variare a seconda del dispositivo.
Inoltre, per impostare gli intervalli di dimensioni supportati del widget, puoi impostare i seguenti attributi:
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
Come specificato dagli attributi precedenti, la larghezza del widget è ridimensionabile da 180 dp a 530 dp e l'altezza è ridimensionabile da 110 dp a 450 dp. Il widget è quindi ridimensionabile da 3x2 a 5x2 celle, a condizione che siano presenti le seguenti condizioni:
- Il dispositivo ha la griglia 5x4.
- Il mapping tra il numero di celle e le dimensioni disponibili in dp segue la tabella che mostra la stima delle dimensioni minime dimensioni in questa pagina.
- Il widget si adatta a questo intervallo di dimensioni.
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);
Supponiamo che il widget utilizzi i layout adattabili definiti negli snippet di codice precedenti. Ciò significa che il layout specificato come R.layout.widget_weather_forecast_small viene utilizzato da 180 dp (minResizeWidth) x 110 dp (minResizeHeight) a 269x279 dp (punti di interruzione successivi - 1). Allo stesso modo, R.layout.widget_weather_forecast_medium viene utilizzato da 270x110 dp a 270x279 dp e R.layout.widget_weather_forecast_large viene utilizzato da 270x280 dp a 530 dp (maxResizeWidth) x 450 dp (maxResizeHeight).
Quando l'utente ridimensiona il widget, il suo aspetto cambia per adattarsi a ogni dimensione in celle, come mostrato negli esempi seguenti.
R.layout.widget_weather_forecast_small.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_medium.
R.layout.widget_weather_forecast_large.
R.layout.widget_weather_forecast_large.