Cette page décrit les améliorations apportées au dimensionnement des widgets et à la flexibilité accrue introduites dans Android 12 (niveau d'API 31). Il explique également comment déterminer la taille de votre widget.
Utiliser des API améliorées pour les tailles et les mises en page de widgets
À partir d'Android 12 (niveau d'API 31), vous pouvez fournir des attributs de taille plus affinés et des mises en page flexibles en procédant comme suit:
Spécifiez d'autres contraintes de dimensionnement des widgets.
fournir des mises en page responsives ou des mises en page exactes ;
Dans les versions précédentes d'Android, il est possible d'obtenir les plages de taille d'un widget à l'aide des extras OPTION_APPWIDGET_MIN_WIDTH
, OPTION_APPWIDGET_MIN_HEIGHT
, OPTION_APPWIDGET_MAX_WIDTH
et OPTION_APPWIDGET_MAX_HEIGHT
, puis d'estimer la taille du widget, mais cette logique ne fonctionne pas dans toutes les situations. Pour les widgets ciblant Android 12 ou version ultérieure, nous vous recommandons de fournir des mises en page responsives ou exactes.
Spécifier des contraintes de taille de widget supplémentaires
Android 12 ajoute des API qui vous permettent de vous assurer que votre widget est dimensionné de manière plus fiable sur différents appareils avec des tailles d'écran différentes.
En plus des attributs minWidth
, minHeight
, minResizeWidth
et minResizeHeight
existants, utilisez les nouveaux attributs appwidget-provider
suivants:
targetCellWidth
ettargetCellHeight
: définissent la taille cible du widget en termes de cellules de la grille du lanceur. S'ils sont définis, ces attributs sont utilisés à la place deminWidth
ouminHeight
.maxResizeWidth
etmaxResizeHeight
: définissez la taille maximale à laquelle le lanceur d'applications permet à l'utilisateur de redimensionner le widget.
Le code XML suivant montre comment utiliser les attributs de taille.
<appwidget-provider
...
android:targetCellWidth="3"
android:targetCellHeight="2"
android:maxResizeWidth="250dp"
android:maxResizeHeight="110dp">
</appwidget-provider>
Fournir des mises en page responsives
Si la mise en page doit changer en fonction de la taille du widget, nous vous recommandons de créer un petit ensemble de mises en page, chacune valide pour une plage de tailles. Si cela n'est pas possible, une autre option consiste à fournir des mises en page basées sur la taille exacte du widget au moment de l'exécution, comme décrit sur cette page.
Cette fonctionnalité permet un scaling plus fluide et un meilleur état général du système, car le système n'a pas besoin de réactiver l'application chaque fois qu'il affiche le widget dans une taille différente.
L'exemple de code suivant montre comment fournir une liste de mises en page.
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); }
Supposons que le widget possède les attributs suivants:
<appwidget-provider
android:minResizeWidth="160dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="250dp"
android:maxResizeHeight="200dp">
</appwidget-provider>
L'extrait de code précédent signifie ce qui suit:
smallView
prend en charge des valeurs allant de 160 dp (minResizeWidth
) × 110 dp (minResizeHeight
) à 160 dp × 199 dp (prochain point limite : 1 dp).tallView
accepte des valeurs comprises entre 160 dp × 200 dp et 214 dp (prochain point limite : 1) × 200 dp.wideView
prend en charge des valeurs allant de 215 dp × 110 dp (minResizeHeight
) à 250 dp (maxResizeWidth
) × 200 dp (maxResizeHeight
).
Votre widget doit accepter une plage de tailles comprise entre minResizeWidth
× minResizeHeight
et maxResizeWidth
× maxResizeHeight
. Dans cette plage, vous pouvez décider du point limite pour changer de mise en page.
![Exemple de mise en page responsive](https://developer.android.google.cn/static/images/appwidgets/size-range.gif?authuser=4&hl=fr)
Fournir une mise en page exacte
Si un petit ensemble de mises en page responsives n'est pas possible, vous pouvez fournir différentes mises en page adaptées aux tailles d'affichage du widget. Il s'agit généralement de deux tailles pour les téléphones (modes portrait et paysage) et de quatre tailles pour les appareils pliables.
Pour implémenter cette solution, votre application doit effectuer les étapes suivantes:
Surcharge
AppWidgetProvider.onAppWidgetOptionsChanged()
, qui est appelé lorsque l'ensemble des tailles change.Appelez
AppWidgetManager.getAppWidgetOptions()
, qui renvoie unBundle
contenant les tailles.Accédez à la clé
AppWidgetManager.OPTION_APPWIDGET_SIZES
à partir deBundle
.
L'exemple de code suivant montre comment fournir des mises en page exactes.
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) { }
Déterminer la taille de votre widget
Chaque widget doit définir des champs targetCellWidth
et targetCellHeight
pour les appareils équipés d'Android 12 ou version ultérieure, ou minWidth
et minHeight
pour toutes les versions d'Android, indiquant la quantité minimale d'espace qu'il utilise par défaut. Toutefois, lorsque les utilisateurs ajoutent un widget à leur écran d'accueil, il occupe généralement plus que la largeur et la hauteur minimales que vous spécifiez.
Les écrans d'accueil Android proposent aux utilisateurs une grille d'espaces disponibles dans lesquels ils peuvent placer des widgets et des icônes. Cette grille peut varier selon l'appareil. Par exemple, de nombreux téléphones sont dotés d'une grille de 5x4, tandis que les tablettes peuvent en présenter une plus grande. Lorsque votre widget est ajouté, il est étiré pour occuper le nombre minimal de cellules (horizontalement et verticalement) requis pour respecter les contraintes targetCellWidth
et targetCellHeight
sur les appareils équipés d'Android 12 ou version ultérieure, ou les contraintes minWidth
et minHeight
sur les appareils équipés d'Android 11 (niveau d'API 30) ou version antérieure.
La largeur et la hauteur d'une cellule ainsi que la taille des marges automatiques appliquées aux widgets peuvent varier d'un appareil à l'autre. Utilisez le tableau suivant pour estimer approximativement les dimensions minimales de votre widget dans un combiné standard doté de grilles 5x4, en fonction du nombre de cellules occupées que vous souhaitez:
Nombre de cellules (largeur x hauteur) | Taille disponible en mode Portrait (dp) | Taille disponible en mode Paysage (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) | (142 n – 15) x (66 m – 15) |
Utilisez les tailles de cellule en mode Portrait pour définir les valeurs que vous fournissez pour les attributs minWidth
, minResizeWidth
et maxResizeWidth
. De même, utilisez les tailles de cellules en mode Paysage pour définir les valeurs que vous fournissez pour les attributs minHeight
, minResizeHeight
et maxResizeHeight
.
En effet, la largeur de cellule est généralement plus faible en mode Portrait qu'en mode Paysage. De même, la hauteur de cellule est généralement plus faible en mode Paysage qu'en mode Portrait.
Par exemple, si vous souhaitez que la largeur de votre widget puisse être redimensionnable à une cellule sur un Google Pixel 4, vous devez définir votre minResizeWidth
sur 56 dp au maximum pour vous assurer que la valeur de l'attribut minResizeWidth
est inférieure à 57 dp, car une cellule fait au moins 57 dp de large en mode portrait.
De même, si vous souhaitez que la hauteur de votre widget puisse être redimensionnable dans une cellule sur le même appareil, vous devez définir votre minResizeHeight
sur 50 dp au maximum pour vous assurer que la valeur de l'attribut minResizeHeight
est inférieure à 51 dp, car une cellule fait au moins 51 dp de haut en mode Paysage.
Chaque widget est redimensionnable dans les plages de tailles comprises entre les attributs minResizeWidth
/minResizeHeight
et maxResizeWidth
/maxResizeHeight
, ce qui signifie qu'il doit s'adapter aux plages de tailles comprises entre eux.
Par exemple, pour définir la taille par défaut du widget sur son emplacement, vous pouvez définir les attributs suivants:
<appwidget-provider
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minWidth="180dp"
android:minHeight="110dp">
</appwidget-provider>
Cela signifie que la taille par défaut du widget est de 3 x 2 cellules, comme spécifié par les attributs targetCellWidth
et targetCellHeight
, ou de 180 × 110 dp, comme spécifié par minWidth
et minHeight
pour les appareils équipés d'Android 11 ou version antérieure. Dans ce dernier cas, la taille des cellules peut
varier en fonction de l’appareil.
De plus, pour définir les plages de tailles acceptées pour votre widget, vous pouvez définir les attributs suivants:
<appwidget-provider
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="530dp"
android:maxResizeHeight="450dp">
</appwidget-provider>
Comme spécifié par les attributs précédents, la largeur du widget peut être redimensionnée de 180 dp à 530 dp, et sa hauteur est redimensionnable de 110 dp à 450 dp. Le widget peut ensuite être redimensionné de 3 x 2 à 5 x 2 cellules, à condition que les conditions suivantes soient remplies:
- L'appareil est doté d'une grille de 5 x 4.
- Le mappage entre le nombre de cellules et la taille disponible en dps suit le tableau indiquant l'estimation des dimensions minimales de cette page.
- Le widget s'adapte à cette plage de tailles.
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);
Supposons que le widget utilise les mises en page responsives définies dans les extraits de code précédents. Cela signifie que la mise en page spécifiée en tant que R.layout.widget_weather_forecast_small
est utilisée de 180 dp (minResizeWidth
) x 110 dp (minResizeHeight
) à 269 x 279 dp (prochains points limites : 1). De même, R.layout.widget_weather_forecast_medium
est utilisé entre 270 x 110 dp et 270 x 279 dp, et R.layout.widget_weather_forecast_large
est utilisé entre 270 x 280 dp et 530 dp (maxResizeWidth
) x 450 dp (maxResizeHeight
).
Lorsque l'utilisateur redimensionne le widget, son apparence change pour s'adapter à chaque taille des cellules, comme illustré dans les exemples suivants.
![Exemple de widget météo dans la plus petite taille de grille 3x2. L'interface utilisateur affiche le nom de l'emplacement (Tokyo), la température (14 °) et un symbole indiquant un temps partiellement nuageux.](https://developer.android.google.cn/static/images/appwidgets/weather-size-3x2.png?authuser=4&hl=fr)
R.layout.widget_weather_forecast_small
: 3 x 2.![Exemple de widget météo au format "moyen" de 4 x 2 Le redimensionnement du widget s'appuie sur toute l'interface utilisateur de la taille de widget précédente, et ajoute le libellé "Nuageux dans l'ensemble" ainsi qu'une prévision des températures de 16h à 19h.](https://developer.android.google.cn/static/images/appwidgets/weather-size-4x2.png?authuser=4&hl=fr)
R.layout.widget_weather_forecast_medium
: 4 x 2.![Exemple de widget météo au format "moyen" de 5 x 2 Si vous redimensionnez le widget de cette manière, vous obtiendrez la même UI que la taille précédente, sauf qu'il est étiré d'une longueur de cellule pour occuper plus d'espace horizontal.](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x2.png?authuser=4&hl=fr)
R.layout.widget_weather_forecast_medium
: 5 x 2.![Exemple de widget météo au format "grand" de 5 x 3 Le redimensionnement du widget s'appuie sur toute l'interface utilisateur des tailles de widget précédentes, et ajoute une vue à l'intérieur du widget contenant une prévision de la météo du mardi et du mercredi. Symboles indiquant un temps ensoleillé ou pluvieux, et des températures maximale et minimale pour chaque jour.](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x3.png?authuser=4&hl=fr)
R.layout.widget_weather_forecast_large
: 5 x 3.![Exemple de widget météo au format "grand" 5 x 4 Le redimensionnement du widget s'appuie sur toute l'interface utilisateur des tailles de widget précédentes, et ajoute les jeudis et vendredis (et les symboles correspondants indiquant le type de météo ainsi que les températures maximale et minimale pour chaque jour).](https://developer.android.google.cn/static/images/appwidgets/weather-size-5x4.png?authuser=4&hl=fr)
R.layout.widget_weather_forecast_large
5 x 4.