Questa pagina descrive come gestire le dimensioni e offrire flessibilità e adattabilità layout con Riepilogo, utilizzando i componenti Riepilogo esistenti.
Utilizza Box
, Column
e Row
Il riepilogo ha tre layout componibili principali:
Box
: posiziona gli elementi sopra un altro. Viene tradotto inRelativeLayout
.Column
: posiziona gli elementi uno dopo l'altro sull'asse verticale. Traduce a unLinearLayout
con orientamento verticale.Row
: posiziona gli elementi uno dopo l'altro sull'asse orizzontale. Traduce a unLinearLayout
con orientamento orizzontale.
Riepilogo supporta gli oggetti Scaffold
. Posiziona Column
, Row
e
Box
componibili all'interno di un determinato oggetto Scaffold
.
![Immagine di un layout di colonne, righe e caselle.](https://developer.android.com/static/develop/ui/compose/images/column_row_box.png?authuser=0000&hl=it)
Ciascuno di questi componibili consente di definire gli allineamenti verticali e orizzontali del suo contenuto e i vincoli di larghezza, altezza, peso modificatori. Inoltre, ogni figlio può definire il proprio modificatore per cambiare lo spazio e posizionamento all'interno dell'elemento principale.
L'esempio seguente mostra come creare un elemento Row
che distribuisce in modo uniforme
i suoi figli orizzontalmente, come illustrato nella Figura 1:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row
riempie la larghezza massima disponibile e poiché ogni figlio ha la stessa
peso, condividono uniformemente lo spazio disponibile. Puoi definire ponderazioni diverse,
dimensioni, spaziature interne o allineamenti per adattare i layout alle tue esigenze.
Utilizza layout scorrevoli
Un altro modo per fornire contenuti adattabili è renderli scorrevoli. Questo è
possibile con l'elemento componibile LazyColumn
. Questo componibile consente di definire
di elementi da visualizzare all'interno di un contenitore scorrevole nel widget dell'app.
I seguenti snippet mostrano diversi modi per definire gli elementi all'interno dell'attributo
LazyColumn
.
Puoi specificare il numero di elementi:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Fornisci singoli elementi:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Fornisci un elenco o un array di elementi:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Puoi anche utilizzare una combinazione degli esempi precedenti:
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") } }
Tieni presente che lo snippet precedente non specifica il itemId
. Specificare i
itemId
aiuta a migliorare il rendimento e a mantenere lo scorrimento
posizione tramite elenco e appWidget
aggiornamenti a partire da Android 12 (per
ad esempio quando aggiungi o rimuovi articoli dall'elenco). Nell'esempio che segue
mostra come specificare un itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
Definisci il SizeMode
Le dimensioni di AppWidget
possono variare a seconda del dispositivo, della scelta dell'utente o di Avvio app.
quindi è importante fornire layout flessibili, come descritto in Fornisci
layout flessibile del widget. La funzionalità Glance semplifica questo processo con SizeMode
e il valore di LocalSize
. Le seguenti sezioni descrivono i tre
diverse.
SizeMode.Single
SizeMode.Single
è la modalità predefinita. Indica che solo un tipo di
che vengano forniti i contenuti; ovvero anche se la dimensione disponibile (AppWidget
) cambia,
la dimensione dei contenuti non viene modificata.
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 // ... } }
Quando utilizzi questa modalità, assicurati che:
- I valori dei metadati delle dimensioni minima e massima sono definiti correttamente in base sulla dimensione dei contenuti.
- I contenuti sono sufficientemente flessibili all'interno dell'intervallo di dimensioni previsto.
In generale, dovresti utilizzare questa modalità quando:
a) AppWidget
ha una dimensione fissa oppure
b) non cambia i contenuti quando viene ridimensionato.
SizeMode.Responsive
Questa modalità è l'equivalente della fornitura di layout adattabili, che consente
GlanceAppWidget
per definire un insieme di layout adattabili limitati da specifiche
dimensioni. Per ogni dimensione definita, i contenuti vengono creati e mappati al
dimensioni quando l'elemento AppWidget
viene creato o aggiornato. Il sistema seleziona quindi
più adatta in base alla dimensione disponibile.
Ad esempio, nel nostro AppWidget
di destinazione, puoi definire tre dimensioni e le relative
contenuti:
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") } } } }
Nell'esempio precedente, il metodo provideContent
viene chiamato tre volte e
mappata alla dimensione definita.
- Nella prima chiamata, la dimensione restituisce
100x100
. I contenuti non includere il pulsante aggiuntivo, né i testi superiore e inferiore. - Nella seconda chiamata, la dimensione restituisce
250x100
. I contenuti includono pulsante aggiuntivo, ma non i testi superiore e inferiore. - Nella terza chiamata, la dimensione restituisce
250x250
. I contenuti includono pulsante aggiuntivo ed entrambi i testi.
SizeMode.Responsive
è una combinazione delle altre due modalità e ti consente di
definiscono i contenuti reattivi entro limiti predefiniti. In generale, questa modalità
ha prestazioni migliori e consente transizioni più fluide quando l'elemento AppWidget
viene ridimensionato.
La tabella seguente mostra il valore della dimensione, in base a SizeMode
e
la dimensione disponibile (AppWidget
):
Dimensioni disponibili | 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 |
* I valori esatti sono solo a scopo dimostrativo. |
SizeMode.Exact
SizeMode.Exact
equivale a fornire layout esatti, che
richiede i contenuti GlanceAppWidget
ogni volta che la dimensione AppWidget
disponibile
(ad esempio, quando l'utente ridimensiona AppWidget
nella schermata Home).
Ad esempio, nel widget di destinazione, è possibile aggiungere un pulsante in più se la larghezza disponibile supera un certo valore.
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") } } } } }
Questa modalità offre più flessibilità rispetto alle altre, ma include alcune avvertenze:
AppWidget
deve essere ricreato completamente ogni volta che le dimensioni cambiano. Questo possono causare problemi di prestazioni e salti nell'interfaccia utente quando i contenuti sono complessi.- Le dimensioni disponibili potrebbero variare a seconda dell'implementazione di Avvio app. Ad esempio, se Avvio app non fornisce l'elenco delle dimensioni, il numero minimo la dimensione massima possibile.
- Nei dispositivi precedenti ad Android 12, la logica di calcolo delle dimensioni potrebbe non funzionare in situazioni diverse.
In generale, dovresti usare questa modalità se non è possibile usare SizeMode.Responsive
(ovvero, un piccolo insieme di layout adattabili non è fattibile).
Accedi alle risorse
Utilizza LocalContext.current
per accedere a qualsiasi risorsa Android, come mostrato in
nell'esempio seguente:
LocalContext.current.getString(R.string.glance_title)
Ti consigliamo di fornire direttamente gli ID risorsa per ridurre le dimensioni del
RemoteViews
e per abilitare risorse dinamiche, ad esempio Dynamic
colori.
Gli elementi componibili e i metodi accettano risorse utilizzando un "provider", come
ImageProvider
o utilizzando un metodo di sovraccarico come
GlanceModifier.background(R.color.blue)
. Ad esempio:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Testo dell'handle
Glance 1.1.0 include un'API per impostare gli stili di testo. Imposta gli stili di testo utilizzando
Attributi fontSize
, fontWeight
o fontFamily
della classe TextStyle.
fontFamily
supporta tutti i caratteri di sistema, come mostrato nell'esempio seguente, ma
I caratteri personalizzati nelle app non sono supportati:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Aggiungi pulsanti composti
I pulsanti composti sono stati introdotti in Android 12. La funzionalità Riepilogo supporta all'indietro compatibilità per i seguenti tipi di pulsanti composti:
Questi pulsanti composti mostrano ciascuno una visualizzazione cliccabile che rappresenta "selezionato" stato.
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" )
Quando lo stato cambia, viene attivato il lambda fornito. Puoi archiviare verifica lo stato, come illustrato nell'esempio seguente:
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) } ) } }
Puoi fornire l'attributo colors
anche a CheckBox
, Switch
e
RadioButton
per personalizzare i colori:
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) ), )
Componenti aggiuntivi
Il Glance 1.1.0 include il rilascio di componenti aggiuntivi, come descritto in tabella seguente:
Nome | Immagine | Link di riferimento | Note aggiuntive |
---|---|---|---|
Pulsante pieno |
![]() |
Componente | |
Pulsanti con contorno |
![]() |
Componente | |
Pulsanti icona |
![]() |
Componente | Principale / Secondario / Solo icone |
Barra del titolo |
![]() |
Componente | |
Impalcatura | Scaffold e Barra del titolo si trovano nella stessa demo. |
Per ulteriori informazioni sulle specifiche del design, consulta le progettazioni dei componenti in questa design kit su Figma.