UI mit Glance erstellen

Auf dieser Seite wird beschrieben, wie mit Größen umgegangen wird und wie flexible und responsive Anzeigen bereitgestellt werden. Layouts mit Glance unter Verwendung vorhandener Glance-Komponenten erstellen.

Box, Column und Row verwenden

Glance hat drei zusammensetzbare Hauptlayouts:

  • Box: Platziert Elemente übereinander. Er wird in RelativeLayout übersetzt.

  • Column: Platziert Elemente hintereinander in der vertikalen Achse. Übersetzung in ein LinearLayout mit vertikaler Ausrichtung.

  • Row: Platziert Elemente hintereinander in der horizontalen Achse. Übersetzung in ein LinearLayout mit horizontaler Ausrichtung.

Glance unterstützt Scaffold-Objekte. Platziere Column, Row und Box-Zusammensetzbare Funktionen innerhalb eines bestimmten Scaffold-Objekts.

<ph type="x-smartling-placeholder">
</ph> Abbildung eines Layouts für Spalte, Zeile und Feld.
Abbildung 1: Beispiele für Layouts mit „Column“, „Row“ und „Box“.

Mit jeder dieser zusammensetzbaren Funktionen können Sie die vertikale und horizontale Ausrichtung festlegen. des Inhalts und die Einschränkungen für Breite, Höhe, Gewicht oder Abstände mithilfe von Modifizierern. Darüber hinaus kann jedes untergeordnete Element seinen Modifikator definieren, um das Leerzeichen Placement innerhalb des übergeordneten Elements.

Im folgenden Beispiel sehen Sie, wie Sie eine Row erstellen, die gleichmäßig verteilt seine untergeordneten Elemente horizontal, wie in Abbildung 1 dargestellt:

Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) {
    val modifier = GlanceModifier.defaultWeight()
    Text("first", modifier)
    Text("second", modifier)
    Text("third", modifier)
}

Row füllt die maximal verfügbare Breite aus. Da jedes untergeordnete Element dieselbe teilen sie sich den verfügbaren Platz gleichmäßig. Sie können unterschiedliche Gewichtungen, Größen, Abstände oder Ausrichtungen, um Layouts an Ihre Anforderungen anzupassen.

Scrollbare Layouts verwenden

Eine weitere Möglichkeit, responsive Inhalte bereitzustellen, besteht darin, sie scrollbar zu machen. Dies ist mit der zusammensetzbaren Funktion LazyColumn möglich. Mit dieser zusammensetzbaren Funktion können Sie von Elementen, die in einem scrollbaren Container im App-Widget angezeigt werden.

Die folgenden Snippets zeigen verschiedene Möglichkeiten zum Definieren von Elementen im LazyColumn

Sie können die Anzahl der Elemente angeben:

// Remember to import Glance Composables
// import androidx.glance.appwidget.layout.LazyColumn

LazyColumn {
    items(10) { index: Int ->
        Text(
            text = "Item $index",
            modifier = GlanceModifier.fillMaxWidth()
        )
    }
}

Stellen Sie einzelne Elemente bereit:

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 wurde itemId nicht angegeben. Angabe des itemId hilft dabei, die Leistung zu verbessern und den Scrollvorgang beizubehalten auf der Liste und appWidget Updates ab Android 12 (für z. B. wenn du Artikel hinzufügst oder entfernst. Im folgenden Beispiel zeigt, wie ein itemId angegeben wird:

items(items = peopleList, key = { person -> person.id }) { person ->
    Text(person.name)
}

SizeMode definieren

AppWidget kann je nach Gerät, Nutzerauswahl oder Launcher variieren. Daher ist es wichtig, flexible Layouts bereitzustellen, wie im Abschnitt Bereitstellung von Seite „Flexible Widget-Layouts“ öffnen. Live-Anzeige erleichtert das mit der SizeMode und den Wert LocalSize. In den folgenden Abschnitten werden die drei Modi.

SizeMode.Single

SizeMode.Single ist der Standardmodus. Es bedeutet, dass nur eine Art von Inhalte zur Verfügung gestellt werden, Das heißt, auch wenn sich die verfügbare Größe von AppWidget ändert, wird die Inhaltsgröße nicht geä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
        // ...
    }
}

Achten Sie bei Verwendung dieses Modus auf Folgendes:

  • Die Metadatenwerte für die Mindest- und Maximalgröße sind korrekt definiert, auf die Inhaltsgröße.
  • Der Inhalt ist innerhalb des erwarteten Größenbereichs ausreichend flexibel.

Im Allgemeinen sollten Sie diesen Modus in folgenden Fällen verwenden:

a) AppWidget eine feste Größe hat oder b) Der Inhalt ändert sich bei der Größenanpassung nicht.

SizeMode.Responsive

Dieser Modus entspricht dem Bereitstellen responsiver Layouts, mit dem GlanceAppWidget, um einen Satz responsiver Layouts zu definieren, die durch bestimmte Größen. Für jede definierte Größe wird der Inhalt erstellt und der spezifischen festgelegt, wenn die AppWidget erstellt oder aktualisiert wird. Das System wählt dann die am besten geeignet für die verfügbare Größe sein.

In unserem Ziel AppWidget können Sie beispielsweise drei Größen definieren und Inhalt:

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 wurde die Methode provideContent dreimal aufgerufen und definierter Größe zugeordnet ist.

  • Im ersten Aufruf wird die Größe als 100x100 ausgewertet. Der Inhalt entspricht nicht die zusätzliche Schaltfläche und den Text oben und unten einfügen.
  • Im zweiten Aufruf wird die Größe als 250x100 ausgewertet. Der Inhalt umfasst die zusätzliche Schaltfläche, aber nicht den oberen und unteren Text.
  • Im dritten Aufruf wird die Größe als 250x250 ausgewertet. Der Inhalt umfasst die und beide Texte verwenden.

SizeMode.Responsive ist eine Kombination der anderen beiden Modi und ermöglicht Ihnen, Responsive Inhalte innerhalb vordefinierter Grenzen zu definieren. Im Allgemeinen bietet dieser Modus ist besser und ermöglicht flüssigere Übergänge, wenn die AppWidget-Größe angepasst wird.

Die folgende Tabelle zeigt den Wert der Größe in Abhängigkeit von SizeMode und die verfügbare Größe von AppWidget:

Verfügbare Größe 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
* Die genauen Werte dienen nur zu Demonstrationszwecken.

SizeMode.Exact

SizeMode.Exact entspricht der Bereitstellung exakter Layouts, fordert den Inhalt GlanceAppWidget jedes Mal an, wenn die verfügbare Größe von AppWidget verfügbar ist (z. B. wenn der Nutzer die Größe von AppWidget auf dem Startbildschirm ändert).

Beispielsweise kann im Ziel-Widget eine zusätzliche Schaltfläche hinzugefügt werden, 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 ist flexibler als die anderen, bietet aber auch Warnungen:

  • Die AppWidget muss bei jeder Größenänderung vollständig neu erstellt werden. Dieses kann bei komplexen Inhalten zu Leistungsproblemen und Sprüngen der Benutzeroberfläche führen.
  • Die verfügbare Größe kann je nach Implementierung des Launchers variieren. Wenn im Launcher beispielsweise keine Liste mit Größen angezeigt wird, mögliche Größe verwendet.
  • Bei Geräten mit einer älteren Version von Android 12 funktioniert die Logik zur Größenberechnung möglicherweise nicht bei allen Situationen.

Im Allgemeinen sollten Sie diesen Modus verwenden, wenn SizeMode.Responsive nicht verwendet werden kann (d. h., eine kleine Gruppe von responsiven Layouts ist nicht praktikabel.)

Auf Ressourcen zugreifen

Verwenden Sie LocalContext.current, um auf jede Android-Ressource zuzugreifen, wie in der folgendes Beispiel:

LocalContext.current.getString(R.string.glance_title)

Wir empfehlen, Ressourcen-IDs direkt anzugeben, um die Größe der finalen RemoteViews-Objekt und zur Aktivierung dynamischer Ressourcen wie dynamischer Farben dargestellt wird.

Composables und Methoden akzeptieren Ressourcen mithilfe eines „Anbieters“, z. B. ImageProvider oder eine Überlastungsmethode wie GlanceModifier.background(R.color.blue). Beispiel:

Column(
    modifier = GlanceModifier.background(R.color.default_widget_background)
) { /**...*/ }

Image(
    provider = ImageProvider(R.drawable.ic_logo),
    contentDescription = "My image",
)

Text verarbeiten

Glance 1.1.0 enthält eine API zum Festlegen Ihrer Textstile. Textstile festlegen mit fontSize-, fontWeight- oder fontFamily-Attribute der TextStyle-Klasse.

fontFamily unterstützt alle Systemschriftarten, wie im folgenden Beispiel gezeigt, aber benutzerdefinierte Schriftarten in Apps werden nicht unterstützt:

Text(
    style = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 18.sp,
        fontFamily = FontFamily.Monospace
    ),
    text = "Example Text"
)

Kombinierte Schaltflächen hinzufügen

Zusammengesetzte Schaltflächen wurden mit Android 12 eingeführt. Mit der Live-Anzeige können Sie Kompatibilität für die folgenden Arten von zusammengesetzten Schaltflächen:

Diese zusammengesetzten Schaltflächen zeigen jeweils eine klickbare Ansicht an, die das "aktiviert" Bundesstaat.

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 die überprüfen, 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 Attribut colors auch für CheckBox, Switch und RadioButton, 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 den folgende Tabelle:

Name Bild Referenzlink Zusätzliche Anmerkungen
Gefüllter Knopf Alt-Text Komponente
Umrissschaltflächen Alt-Text Komponente
Symbolschaltflächen Alt-Text Komponente Primär / Sekundär / Nur Symbol
Titelleiste Alt-Text Komponente
Gerüst Gerüst und Titelleiste befinden sich in derselben Demo.