Auf dieser Seite wird beschrieben, wie Sie mit Glance Größen verwalten und flexible und responsive Layouts erstellen, indem Sie vorhandene Glance-Komponenten verwenden.
Verwende Box
, Column
und Row
.
Glance bietet drei Hauptlayouts, die kombiniert werden können:
Box
: Hiermit werden Elemente übereinander gelegt. Sie wird in einenRelativeLayout
umgewandelt.Column
: Hiermit werden Elemente in der vertikalen Achse nacheinander angeordnet. Das entspricht einemLinearLayout
mit vertikaler Ausrichtung.Row
: Hiermit werden Elemente in der horizontalen Achse hintereinander angeordnet. Das entspricht einemLinearLayout
mit horizontaler Ausrichtung.
Glance unterstützt Scaffold
-Objekte. Platzieren Sie Ihre Column
-, Row
- und Box
-Kompositionen in einem bestimmten Scaffold
-Objekt.
Bei jedem dieser Elemente können Sie die vertikale und horizontale Ausrichtung des Inhalts sowie die Einschränkungen für Breite, Höhe, Gewicht oder Abstand mithilfe von Modifikatoren festlegen. Außerdem kann jedes untergeordnete Element einen eigenen Modifikator definieren, um den Abstand und die Platzierung innerhalb des übergeordneten Elements zu ändern.
Im folgenden Beispiel wird gezeigt, wie Sie ein Row
erstellen, bei dem die untergeordneten Elemente wie in Abbildung 1 horizontal gleichmäßig verteilt sind:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Das Row
füllt die maximal verfügbare Breite aus. Da jedes Kind dasselbe Gewicht hat, teilen sie sich den verfügbaren Platz gleichmäßig auf. Sie können unterschiedliche Gewichtungen, Größen, Abstände oder Ausrichtungen festlegen, um Layouts an Ihre Anforderungen anzupassen.
Scrollbare Layouts verwenden
Eine weitere Möglichkeit, responsive Inhalte bereitzustellen, besteht darin, sie scrollbar zu machen. Das ist mit der LazyColumn
-Komposition möglich. Mit diesem Composeable können Sie eine Reihe von Elementen definieren, die in einem scrollbaren Container im App-Widget angezeigt werden sollen.
Die folgenden Snippets zeigen verschiedene Möglichkeiten, Elemente in LazyColumn
zu definieren.
Sie können die Anzahl der Artikel so angeben:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Geben Sie einzelne Elemente an:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Geben Sie eine Liste oder ein Array von Elementen an:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Sie können auch eine Kombination der vorherigen Beispiele verwenden:
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") } }
Im vorherigen Snippet ist das itemId
nicht angegeben. Wenn Sie itemId
angeben, lässt sich die Leistung verbessern und die Scrollposition bei Listen- und appWidget
-Aktualisierungen ab Android 12 beibehalten (z. B. beim Hinzufügen oder Entfernen von Elementen aus der Liste). Das folgende Beispiel zeigt, wie eine itemId
angegeben wird:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
SizeMode
definieren
Die Größe von AppWidget
kann je nach Gerät, Nutzerauswahl oder Launcher variieren. Daher ist es wichtig, flexible Layouts bereitzustellen, wie auf der Seite Flexible Widget-Layouts bereitstellen beschrieben. In Glance wird dies durch die SizeMode
-Definition und den LocalSize
-Wert vereinfacht. In den folgenden Abschnitten werden die drei Modi beschrieben.
SizeMode.Single
SizeMode.Single
ist der Standardmodus. Es gibt an, dass nur ein Inhaltstyp bereitgestellt wird. Das bedeutet, dass sich die Inhaltsgröße nicht ändert, auch wenn sich die verfügbare AppWidget
-Größe ändert.
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 // ... } }
Beachten Sie bei der Verwendung dieses Modus Folgendes:
- Die Metadatenwerte für die Mindest- und Maximalgröße sind korrekt anhand der Inhaltsgröße definiert.
- Die Inhalte sind innerhalb des erwarteten Größenbereichs flexibel genug.
Im Allgemeinen sollten Sie diesen Modus verwenden, wenn:
a) Die AppWidget
hat eine feste Größe oder b) der Inhalt ändert sich nicht, wenn die Größe geändert wird.
SizeMode.Responsive
Dieser Modus entspricht dem Anbieten responsiver Layouts. Damit kann die GlanceAppWidget
eine Reihe responsiver Layouts mit bestimmten Größen definieren. Für jede definierte Größe werden die Inhalte erstellt und der jeweiligen Größe zugeordnet, wenn die AppWidget
erstellt oder aktualisiert wird. Das System wählt dann anhand der verfügbaren Größe die am besten passende Option aus.
Für das Ziel AppWidget
können Sie beispielsweise drei Größen und den Inhalt definieren:
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") } } } }
Im vorherigen Beispiel wird die Methode provideContent
dreimal aufgerufen und der definierten Größe zugeordnet.
- Beim ersten Aufruf wird die Größe zu
100x100
ausgewertet. Der Inhalt enthält weder die zusätzliche Schaltfläche noch den Text oben und unten. - Beim zweiten Aufruf wird der Wert
250x100
zurückgegeben. Der Inhalt enthält die zusätzliche Schaltfläche, aber nicht den Text oben und unten. - Beim dritten Aufruf ergibt die Größe
250x250
. Der Inhalt umfasst die zusätzliche Schaltfläche und beide Texte.
SizeMode.Responsive
ist eine Kombination der beiden anderen Modi und ermöglicht es Ihnen, responsive Inhalte innerhalb vordefinierter Grenzen zu definieren. Im Allgemeinen ist dieser Modus leistungsfähiger und ermöglicht flüssigere Übergänge, wenn die Größe der AppWidget
geändert wird.
In der folgenden Tabelle sehen Sie den Wert der Größe, abhängig von der verfügbaren Größe von SizeMode
und AppWidget
:
Verfügbare Größe | 105 × 110 | 203 × 112 | 72 × 72 | 203 × 150 |
---|---|---|---|---|
SizeMode.Single |
110 × 110 | 110 × 110 | 110 × 110 | 110 × 110 |
SizeMode.Exact |
105 × 110 | 203 × 112 | 72 × 72 | 203 × 150 |
SizeMode.Responsive |
80 × 100 | 80 × 100 | 80 × 100 | 150 × 120 |
* Die genauen Werte dienen nur zu Demonstrationszwecken. |
SizeMode.Exact
SizeMode.Exact
entspricht dem Angeben genauer Layouts, bei dem die GlanceAppWidget
-Inhalte jedes Mal angefordert werden, wenn sich die verfügbare AppWidget
-Größe ändert (z. B. wenn der Nutzer die Größe der AppWidget
auf dem Startbildschirm ändert).
So kann beispielsweise im Ziel-Widget eine zusätzliche Schaltfläche hinzugefügt werden, wenn die verfügbare Breite größer als ein bestimmter Wert ist.
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") } } } } }
Dieser Modus bietet mehr Flexibilität als die anderen, hat aber einige Nachteile:
- Die
AppWidget
muss bei jeder Größenänderung vollständig neu erstellt werden. Das kann bei komplexen Inhalten zu Leistungsproblemen und UI-Sprüngen führen. - Die verfügbare Größe kann je nach Implementierung des Launchers variieren. Wenn der Launcher beispielsweise keine Liste der Größen anbietet, wird die kleinstmögliche Größe verwendet.
- Auf Geräten mit einer älteren Android-Version funktioniert die Logik zur Größeberechnung möglicherweise nicht in allen Fällen.
Im Allgemeinen sollten Sie diesen Modus verwenden, wenn SizeMode.Responsive
nicht verwendet werden kann, d. h. wenn nur eine kleine Anzahl responsiver Layouts möglich ist.
Auf Ressourcen zugreifen
Verwenden Sie LocalContext.current
, um auf eine beliebige Android-Ressource zuzugreifen, wie im folgenden Beispiel gezeigt:
LocalContext.current.getString(R.string.glance_title)
Wir empfehlen, Ressourcen-IDs direkt anzugeben, um die Größe des endgültigen RemoteViews
-Objekts zu reduzieren und dynamische Ressourcen wie dynamische Farben zu aktivieren.
In Composables und Methoden werden Ressourcen über einen „Anbieter“ wie ImageProvider
oder über eine Überladung wie GlanceModifier.background(R.color.blue)
akzeptiert. Beispiel:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Text bearbeiten
Glance 1.1.0 enthält eine API zum Festlegen von Textstilen. Legen Sie Textstile mit den Attributen fontSize
, fontWeight
oder fontFamily
der TextStyle-Klasse fest.
fontFamily
unterstützt alle Systemschriften, wie im folgenden Beispiel gezeigt. Benutzerdefinierte Schriftarten in Apps werden jedoch nicht unterstützt:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Zusammengesetzte Schaltflächen hinzufügen
Zusammengesetzte Schaltflächen wurden in Android 12 eingeführt. Glance unterstützt die Abwärtskompatibilität für die folgenden Arten von zusammengesetzten Schaltflächen:
Diese zusammengesetzten Schaltflächen enthalten jeweils eine anklickbare Ansicht, die den Status „angeklickt“ darstellt.
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" )
Wenn sich der Status ändert, wird das angegebene Lambda ausgelöst. Sie können den Prüfstatus speichern, wie im folgenden Beispiel gezeigt:
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) } ) } }
Sie können das colors
-Attribut auch für CheckBox
, Switch
und RadioButton
angeben, um die Farben anzupassen:
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) ), )
Zusätzliche Komponenten
Glance 1.1.0 enthält die Veröffentlichung zusätzlicher Komponenten, wie in der folgenden Tabelle beschrieben:
Name | Bild | Referenzlink | Zusätzliche Anmerkungen |
---|---|---|---|
Gefüllte Schaltfläche | Komponente | ||
Schaltflächen mit Umriss | Komponente | ||
Symbolschaltflächen | Komponente | Primär / Sekundär / Nur Symbol | |
Titelleiste | Komponente | ||
Gerüst | Scaffold und Titelleiste befinden sich in derselben Demo. |
Weitere Informationen zu Designdetails finden Sie in den Komponentendesigns in diesem Designkit in Figma.
Weitere Informationen zu kanonischen Layouts finden Sie unter Kanonische Widget-Layouts.