Cette page explique comment gérer les tailles et proposer des solutions flexibles et responsives. mises en page avec Glance, à l'aide des composants Glance existants.
Utiliser Box
, Column
et Row
Glance propose trois mises en page composables principales:
Box
: place les éléments les uns sur les autres. Cela se traduit parRelativeLayout
.Column
: place les éléments les uns après les autres sur l'axe vertical. Traduction enLinearLayout
avec une orientation verticale.Row
: place les éléments les uns après les autres sur l'axe horizontal. Traduction enLinearLayout
avec une orientation horizontale.
Glance prend en charge les objets Scaffold
. Placez vos Column
, Row
et
Composables Box
dans un objet Scaffold
donné.
Chacun de ces composables vous permet de définir les alignements vertical et horizontal de son contenu et les contraintes de largeur, de hauteur, de poids ou de marge intérieure à l'aide de modificateurs de requête large. De plus, chaque enfant peut définir son modificateur pour modifier l'espace et le placement dans le parent.
L'exemple suivant montre comment créer un Row
qui répartit équitablement
ses enfants horizontalement, comme illustré dans la figure 1:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row
remplit la largeur maximale disponible, et comme chaque élément enfant a le même
ils partagent uniformément l'espace disponible. Vous pouvez définir différentes pondérations,
des tailles, des marges intérieures ou des alignements pour adapter les mises en page à vos besoins.
Utiliser des mises en page à défilement
Une autre façon de fournir du contenu responsif consiste à le rendre déroulant. C'est
possible avec le composable LazyColumn
. Ce composable vous permet de définir un ensemble
d'éléments à afficher dans un conteneur déroulant du widget d'application.
Les extraits de code suivants montrent différentes manières de définir des éléments dans
LazyColumn
Vous pouvez indiquer le nombre d'éléments:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Fournissez des éléments individuels:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Fournissez une liste ou un tableau d'éléments:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Vous pouvez également utiliser une combinaison des exemples précédents:
LazyColumn { item { Text("Names:") } items(peopleNameList) { name -> Text(name) } // or in case you need the index: itemsIndexed(peopleNameList) { index, person -> Text("$person at index $index") } }
Notez que l'extrait précédent ne spécifie pas le itemId
. Spécifier le paramètre
itemId
permet d'améliorer les performances et de maintenir le défilement.
de position via la liste et les mises à jour appWidget
à partir d'Android 12 (pour les
lors de l'ajout ou de la suppression d'éléments dans la liste, par exemple). L'exemple suivant
montre comment spécifier un itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
Définir SizeMode
La taille des AppWidget
peut varier en fonction de l'appareil, du choix de l'utilisateur ou du lanceur d'applications.
il est donc important de proposer des mises en page flexibles, comme décrit dans la section Fournir
les mises en page de widgets flexibles. Glance simplifie cela avec SizeMode
la définition et la valeur LocalSize
. Les sections suivantes décrivent
différents modes.
SizeMode.Single
SizeMode.Single
est le mode par défaut. Il indique qu'un seul type
si le contenu est fourni ; Autrement dit, même si la taille disponible AppWidget
change,
la taille du contenu reste inchangée.
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Single override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the minimum size or resizable // size defined in the App Widget metadata val size = LocalSize.current // ... } }
Lorsque vous utilisez ce mode, vérifiez les points suivants:
- Les valeurs de métadonnées des tailles minimale et maximale sont correctement définies sur la taille du contenu.
- Le contenu est suffisamment flexible par rapport à la plage de tailles prévue.
En général, vous devez utiliser ce mode dans les cas suivants:
a) la AppWidget
a une taille fixe ; ou
b) Elle ne modifie pas son contenu lorsqu'elle est redimensionnée.
SizeMode.Responsive
Ce mode équivaut à fournir des mises en page responsives, qui permet
GlanceAppWidget
pour définir un ensemble de mises en page responsives limitées par des valeurs
différentes tailles d'écran. Pour chaque taille définie, le contenu est créé et mappé sur la
lors de la création ou de la mise à jour de AppWidget
. Le système sélectionne ensuite
le mieux ajusté en fonction de la taille disponible.
Par exemple, dans notre AppWidget
de destination, vous pouvez définir trois tailles et
contenu:
class MyAppWidget : GlanceAppWidget() { companion object { private val SMALL_SQUARE = DpSize(100.dp, 100.dp) private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp) private val BIG_SQUARE = DpSize(250.dp, 250.dp) } override val sizeMode = SizeMode.Responsive( setOf( SMALL_SQUARE, HORIZONTAL_RECTANGLE, BIG_SQUARE ) ) override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be one of the sizes defined above. val size = LocalSize.current Column { if (size.height >= BIG_SQUARE.height) { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) } Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width >= HORIZONTAL_RECTANGLE.width) { Button("School") } } if (size.height >= BIG_SQUARE.height) { Text(text = "provided by X") } } } }
Dans l'exemple précédent, la méthode provideContent
est appelée trois fois.
mappée à la taille définie.
- Dans le premier appel, la taille est évaluée à
100x100
. Le contenu n'est pas inclure le bouton supplémentaire, ni les textes du haut et du bas. - Dans le deuxième appel, la taille est évaluée à
250x100
. Le contenu inclut les bouton supplémentaire, mais pas les textes du haut et du bas. - Dans le troisième appel, la taille est évaluée à
250x250
. Le contenu inclut les bouton supplémentaire et les deux textes.
SizeMode.Responsive
, qui combine les deux autres modes, vous permet
définir du contenu réactif dans des limites prédéfinies. En général, ce mode
fonctionne mieux et permet des transitions plus fluides lorsque AppWidget
est redimensionné.
Le tableau suivant indique la valeur de la taille en fonction de SizeMode
et
la taille AppWidget
disponible:
Taille disponible | 105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
---|---|---|---|---|
SizeMode.Single |
110 x 110 | 110 x 110 | 110 x 110 | 110 x 110 |
SizeMode.Exact |
105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
SizeMode.Responsive |
80 x 100 | 80 x 100 | 80 x 100 | 150 x 120 |
* Les valeurs exactes ne sont utilisées qu'à titre de démonstration. |
SizeMode.Exact
SizeMode.Exact
équivaut à fournir des mises en page exactes, ce qui
demande le contenu GlanceAppWidget
chaque fois que la taille AppWidget
disponible
(par exemple, lorsque l'utilisateur redimensionne AppWidget
dans l'écran d'accueil).
Par exemple, dans le widget de destination, un bouton supplémentaire peut être ajouté si le disponible est supérieure à une certaine valeur.
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Exact override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the size of the AppWidget val size = LocalSize.current Column { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width > 250.dp) { Button("School") } } } } }
Ce mode offre plus de flexibilité que les autres, mais il est associé à mises en garde:
- La
AppWidget
doit être entièrement recréée chaque fois que la taille change. Ce peut entraîner des problèmes de performances et des sauts dans l'interface utilisateur lorsque le contenu est complexe. - La taille disponible peut varier en fonction de l'implémentation du lanceur d'applications. Par exemple, si le lanceur d'applications ne fournit pas la liste des tailles, la configuration minimale la taille possible est utilisée.
- Sur les appareils antérieurs à Android 12, il est possible que la logique de calcul de la taille ne fonctionne pas situations différentes.
En général, vous devez utiliser ce mode si SizeMode.Responsive
ne peut pas être utilisé
(c'est-à-dire qu'un petit ensemble de mises en page responsives n'est pas possible).
Accéder aux ressources
Utilisez LocalContext.current
pour accéder à n'importe quelle ressource Android, comme indiqué dans le
l'exemple suivant:
LocalContext.current.getString(R.string.glance_title)
Nous vous recommandons d'indiquer directement les ID de ressource afin de réduire la taille du fichier final
RemoteViews
et pour activer les ressources dynamiques, telles que les
couleurs.
Les composables et les méthodes acceptent les ressources qui utilisent un "fournisseur", comme
ImageProvider
, ou à l'aide d'une méthode de surcharge telle que
GlanceModifier.background(R.color.blue)
Exemple :
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Gérer le texte
Glance 1.1.0 inclut une API permettant de définir vos styles de texte. Définir des styles de texte à l'aide de
Attributs fontSize
, fontWeight
ou fontFamily
de la classe TextStyle.
fontFamily
accepte toutes les polices système, comme illustré dans l'exemple suivant, mais
les polices personnalisées ne sont pas acceptées dans les applications:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Ajouter des boutons composés
Les boutons composés ont été introduits dans Android 12. Glance prend en charge l'arrière-plan Compatibilité avec les types de boutons composés suivants:
Ces boutons composés affichent chacun une vue cliquable qui représente "coché" de l'état.
var isApplesChecked by remember { mutableStateOf(false) } var isEnabledSwitched by remember { mutableStateOf(false) } var isRadioChecked by remember { mutableStateOf(0) } CheckBox( checked = isApplesChecked, onCheckedChange = { isApplesChecked = !isApplesChecked }, text = "Apples" ) Switch( checked = isEnabledSwitched, onCheckedChange = { isEnabledSwitched = !isEnabledSwitched }, text = "Enabled" ) RadioButton( checked = isRadioChecked == 1, onClick = { isRadioChecked = 1 }, text = "Checked" )
Lorsque l'état change, le lambda fourni est déclenché. Vous pouvez stocker l'état de vérification, comme illustré dans l'exemple suivant:
class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { val myRepository = MyRepository.getInstance() provideContent { val scope = rememberCoroutineScope() val saveApple: (Boolean) -> Unit = { scope.launch { myRepository.saveApple(it) } } MyContent(saveApple) } } @Composable private fun MyContent(saveApple: (Boolean) -> Unit) { var isAppleChecked by remember { mutableStateOf(false) } Button( text = "Save", onClick = { saveApple(isAppleChecked) } ) } }
Vous pouvez également fournir l'attribut colors
à CheckBox
, Switch
et
RadioButton
pour personnaliser leurs couleurs:
CheckBox( // ... colors = CheckboxDefaults.colors( checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight), uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked } ) Switch( // ... colors = SwitchDefaults.colors( checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan), uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta), checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow), uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked }, text = "Enabled" ) RadioButton( // ... colors = RadioButtonDefaults.colors( checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow), uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue) ), )
Composants supplémentaires
Glance 1.1.0 inclut la publication de composants supplémentaires, comme décrit dans le tableau suivant:
Nom | Image | Lien de référence | Remarques supplémentaires |
---|---|---|---|
Bouton rempli | Composant | ||
Boutons avec contours | Composant | ||
Boutons des icônes | Composant | Primaire / Secondaire / Icône uniquement | |
Barre de titre | Composant | ||
Scaffold | L'échafaudage et la barre de titre sont dans la même démo. |
Pour en savoir plus sur les spécificités de conception, consultez les conceptions de composants dans ce kit de conception sur Figma.