1. Einführung
Was sind Widgets?
Für Flutter-Entwickler bezieht sich die allgemeine Definition von Widget auf UI-Komponenten, die mit dem Flutter-Framework erstellt wurden. Im Kontext dieses Codelabs bezieht sich ein Widget auf eine Miniversion einer App, die einen Einblick in die Informationen der App bietet, ohne die App zu öffnen. Auf Android-Geräten befinden sich Widgets auf dem Startbildschirm. Auf iOS-Geräten können sie dem Start-, Sperrbildschirm oder der Ansicht „Heute“ hinzugefügt werden.
Wie komplex kann ein Widget sein?
Die meisten Startbildschirm-Widgets sind einfach aufgebaut. Sie können einfachen Text, einfache Grafiken oder unter Android grundlegende Steuerelemente enthalten. Sowohl für Android als auch für iOS sind die UI-Komponenten und -Funktionen begrenzt, die Sie verwenden können.
Benutzeroberfläche für Widgets erstellen
Aufgrund dieser Einschränkungen der Benutzeroberfläche können Sie die Benutzeroberfläche eines Startbildschirm-Widgets nicht direkt mit dem Flutter-Framework zeichnen. Stattdessen können Sie Ihrer Flutter-App Widgets hinzufügen, die mit Plattform-Frameworks wie Jetpack Compose oder SwiftUI erstellt wurden. In diesem Codelab werden Beispiele für die gemeinsame Nutzung von Ressourcen zwischen Ihrer App und den Widgets erläutert, um das Umschreiben komplexer Benutzeroberflächen zu vermeiden.
Inhalt
In diesem Codelab erstellen Sie mit dem „home_widget“-Paket Startbildschirm-Widgets für Android und iOS für eine einfache Flutter-App, über die Nutzer Artikel lesen können. Für Ihre Widgets gilt Folgendes:
- Daten aus der Flutter-App anzeigen.
- Anzeigetext mithilfe von Schrift-Assets, die über die Flutter App freigegeben wurden
- Zeigt das Bild eines gerenderten Flutter-Widgets an.
Diese Flutter-App enthält zwei Bildschirme (oder Routen):
- Die erste enthält eine Liste von Nachrichtenartikeln mit Überschriften und Beschreibungen.
- Das zweite Feld zeigt den vollständigen Artikel mit einem Diagramm an, das mit
CustomPaint
erstellt wurde.
.
Lerninhalte
- Startbildschirm-Widgets für iOS und Android erstellen
- Informationen zum Teilen von Daten zwischen dem Startbildschirm-Widget und der Flutter-App mithilfe des Pakets „home_widget“
- So reduzieren Sie die Menge an Code, den Sie neu schreiben müssen.
- So aktualisieren Sie das Startbildschirm-Widget über die Flutter App.
2. Entwicklungsumgebung einrichten
Für beide Plattformen benötigen Sie das Flutter SDK und eine IDE. Sie können Ihre bevorzugte IDE verwenden, um mit Flutter zu arbeiten. Dies kann Visual Studio Code mit den Dart Code- und Flutter-Erweiterungen oder Android Studio oder IntelliJ mit den installierten Flutter- und Dart-Plug-ins sein.
So erstellst du das iOS-Startbildschirm-Widget:
- Du kannst dieses Codelab auf einem physischen iOS-Gerät oder im iOS-Simulator ausführen.
- Sie müssen ein macOS-System mit der Xcode IDE konfigurieren. Dadurch wird der Compiler installiert, der zum Erstellen der iOS-Version Ihrer App erforderlich ist.
So erstellst du das Android-Startbildschirm-Widget:
- Du kannst dieses Codelab auf einem physischen Android-Gerät oder im Android-Emulator ausführen.
- Sie müssen Ihr Entwicklungssystem mit Android Studio konfigurieren. Dadurch wird der Compiler installiert, der zum Erstellen der Android-Version Ihrer App erforderlich ist.
Startercode abrufen
Erste Version Ihres Projekts von GitHub herunterladen
Klonen Sie über die Befehlszeile das GitHub-Repository in ein Flutter-Codelabs-Verzeichnis:
$ git clone https://github.com/flutter/codelabs.git flutter-codelabs
Nachdem Sie das Repository geklont haben, finden Sie den Code für dieses Codelab im Verzeichnis „flutter-codelabs/homescreen_codelab“. Dieses Verzeichnis enthält fertigen Projektcode für jeden Schritt im Codelab.
Starter App öffnen
Öffnen Sie das Verzeichnis flutter-codelabs/homescreen_codelab/step_03
in Ihrer bevorzugten IDE.
Pakete installieren
Alle erforderlichen Pakete wurden der Datei pubspec.yaml des Projekts hinzugefügt. Führen Sie den folgenden Befehl aus, um die Projektabhängigkeiten abzurufen:
$ flutter pub get
3. Einfaches Startbildschirm-Widget hinzufügen
Fügen Sie zuerst mithilfe der nativen Plattformtools das Startbildschirm-Widget hinzu.
Einfaches Widget für den iOS-Startbildschirm erstellen
Das Hinzufügen einer App-Erweiterung zu Ihrer Flutter-iOS-App funktioniert ähnlich wie das Hinzufügen einer App-Erweiterung zu einer SwiftUI- oder UIKit-App:
- Führen Sie
open ios/Runner.xcworkspace
in einem Terminalfenster aus Ihrem Flutter-Projektverzeichnis aus. Alternativ können Sie in VSCode mit der rechten Maustaste auf den Ordner ios klicken und In Xcode öffnen auswählen. Dadurch wird der Xcode-Standardarbeitsbereich in Ihrem Flutter-Projekt geöffnet. - Wählen Sie im Menü Datei → Neu → Ziel aus. Dadurch wird dem Projekt ein neues Ziel hinzugefügt.
- Eine Liste mit Vorlagen wird angezeigt. Wählen Sie Widget-Erweiterung aus.
- Geben Sie „NewsWidgets“ ein. in das Feld Produktname für dieses Widget ein. Deaktivieren Sie die Kästchen Include Live Activity (Live-Aktivität einschließen) und Include Configuration Intent.
Beispielcode prüfen
Wenn Sie ein neues Ziel hinzufügen, generiert Xcode Beispielcode basierend auf der ausgewählten Vorlage. Weitere Informationen zum generierten Code und zum WidgetKit finden Sie in der Dokumentation zur App-Erweiterung von Apple.
Fehler im Beispiel-Widget beheben und testen
- Aktualisieren Sie zuerst die Konfiguration Ihrer Flutter-App. Sie müssen dies tun, wenn Sie in Ihrer Flutter-App neue Pakete hinzufügen und planen, ein Ziel aus Xcode im Projekt auszuführen. Führen Sie den folgenden Befehl im Verzeichnis Ihrer Flutter-Anwendung aus, um die Konfiguration Ihrer Anwendung zu aktualisieren:
$ flutter build ios --config-only
- Klicken Sie auf Runner, um eine Liste mit Zielen aufzurufen. Wählen Sie „NewsWidgets“ das soeben erstellte Widget-Ziel aus und klicken Sie auf Ausführen. Führen Sie das Widget-Ziel über Xcode aus, wenn Sie den Code des iOS-Widgets ändern.
- Auf dem Simulator oder Gerätebildschirm sollte ein einfaches Startbildschirm-Widget angezeigt werden. Wenn Sie es nicht sehen, können Sie es dem Bildschirm hinzufügen. Klicken Sie auf den Startbildschirm, halten Sie die Maustaste gedrückt und klicken Sie links oben auf das +.
- Suchen Sie nach dem Namen der App. Suchen Sie für dieses Codelab nach „Homescreen Widgets“ (Startbildschirm-Widgets)
- Nachdem Sie das Startbildschirm-Widget hinzugefügt haben, sollte es einen einfachen Text mit der Uhrzeit anzeigen.
Einfaches Android-Widget erstellen
- Wenn Sie ein Startbildschirm-Widget in Android hinzufügen möchten, öffnen Sie die Build-Datei des Projekts in Android Studio. Sie finden diese Datei unter android/build.gradle. Alternativ können Sie in VSCode mit der rechten Maustaste auf den Ordner android klicken und In Android Studio öffnen auswählen.
- Suchen Sie nach der Erstellung des Projekts nach dem App-Verzeichnis in der oberen linken Ecke. Fügen Sie diesem Verzeichnis Ihr neues Startbildschirm-Widget hinzu. Klicken Sie mit der rechten Maustaste auf das Verzeichnis und wählen Sie New -> Widget -> App-Widget
- Android Studio zeigt ein neues Formular an. Grundlegende Informationen zum Startbildschirm-Widget hinzufügen, einschließlich Klassenname, Platzierung, Größe und Ausgangssprache
Legen Sie für dieses Codelab die folgenden Werte fest:
- Class Name (Kursname) zu NewsWidget hinzufügen.
- Drop-down-Menü Minimale Breite (Zellen) auf 3
- Drop-down-Menü Mindesthöhe (Zellen) auf 3
Beispielcode prüfen
Wenn Sie das Formular senden, werden in Android Studio mehrere Dateien erstellt und aktualisiert. Die für dieses Codelab relevanten Änderungen sind in der Tabelle unten aufgeführt
Aktion | Zieldatei | Ändern |
Aktualisieren |
| Fügt einen neuen Empfänger hinzu, der das NewsWidget registriert. |
Erstellen |
| Definiert die Benutzeroberfläche des Startbildschirm-Widgets. |
Erstellen |
| Definiert die Konfiguration des Startbildschirm-Widgets. Sie können die Abmessungen oder den Namen Ihres Widgets in dieser Datei anpassen. |
Erstellen |
| Enthält Ihren Kotlin-Code, um dem Startbildschirm-Widget Funktionen hinzuzufügen. |
In diesem Codelab finden Sie weitere Informationen zu diesen Dateien.
Fehler im Beispiel-Widget beheben und testen
Führen Sie nun Ihre Anwendung aus und sehen Sie sich das Startbildschirm-Widget an. Gehen Sie nach dem Erstellen der App zum App-Auswahlbildschirm Ihres Android-Geräts und drücken Sie lange auf das Symbol für dieses Flutter-Projekt. Wählen Sie im Pop-up-Menü Widgets aus.
Auf dem Android-Gerät oder im Emulator wird das standardmäßige Startbildschirm-Widget für Android angezeigt.
4. Daten von der Flutter App an das Startbildschirm-Widget senden
Sie können das einfache Startbildschirm-Widget, das Sie erstellt haben, anpassen. Aktualisieren Sie das Startbildschirm-Widget, um eine Schlagzeile und eine Zusammenfassung eines Nachrichtenartikels anzuzeigen. Der folgende Screenshot zeigt ein Beispiel für das Startbildschirm-Widget mit einer Überschrift und einer Zusammenfassung.
Um Daten zwischen der App und dem Startbildschirm-Widget zu übertragen, müssen Sie Dart-und nativen Code schreiben. In diesem Abschnitt wird dieser Prozess in drei Teile unterteilt:
- Dart-Code in der Flutter-App schreiben, den Android und iOS verwenden können
- Native iOS-Funktionen hinzufügen
- Native Android-Funktionen hinzufügen
iOS-App-Gruppen verwenden
Wenn Sie Daten zwischen einer übergeordneten iOS-App und einer Widget-Erweiterung teilen möchten, müssen beide Ziele derselben App-Gruppe angehören. Weitere Informationen zu App-Gruppen finden Sie in der Dokumentation zu App-Gruppen von Apple.
Aktualisiere deinen Paket-Identifikator:
Rufen Sie in Xcode die Einstellungen des Ziels auf. Klicken Sie im Dialogfeld Signieren und Funktionen können Sie überprüfen, ob Ihr Team und Ihre Bundle-ID festgelegt sind.
Fügen Sie die App-Gruppe dem Runner-Ziel und dem NewsWidgetExtension-Ziel in Xcode hinzu:
Wählen Sie + Funktion -> App-Gruppen und fügen Sie eine neue App-Gruppe hinzu. Wiederholen Sie diese Schritte sowohl für das Runner-Ziel (übergeordnete App) als auch für das Widget-Ziel.
Dart-Code hinzufügen
Sowohl iOS- als auch Android-Apps können auf unterschiedliche Weise Daten mit einer Flutter-App teilen.Wenn Sie mit diesen Apps kommunizieren möchten, nutzen Sie den lokalen key/value
-Shop des Geräts. Auf iOS-Geräten wird das Geschäft als UserDefaults
und bei Android unter der Bezeichnung SharedPreferences
aufgeführt. Das home_widget-Paket umfasst diese APIs, um das Speichern von Daten auf beiden Plattformen zu vereinfachen und den Startbildschirm-Widgets das Abrufen aktualisierter Daten zu ermöglichen.
Die Daten für Anzeigentitel und Textzeile stammen aus der Datei news_data.dart
. Diese Datei enthält simulierte Daten und eine NewsArticle
-Datenklasse.
lib/news_data.dart
class NewsArticle {
final String title;
final String description;
final String? articleText;
NewsArticle({
required this.title,
required this.description,
this.articleText = loremIpsum,
});
}
Werte für Anzeigentitel und Textzeile aktualisieren
Wenn Sie die Funktion zum Aktualisieren des Startbildschirm-Widgets über die Flutter App hinzufügen möchten, gehen Sie zur Datei lib/home_screen.dart
. Ersetzen Sie den Inhalt der Datei durch den folgenden Code. Ersetzen Sie dann <YOUR APP GROUP>
durch die ID Ihrer App-Gruppe.
lib/home_screen.dart
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart'; // Add this import
import 'article_screen.dart';
import 'news_data.dart';
// TODO: Replace with your App Group ID
const String appGroupId = '<YOUR APP GROUP>'; // Add from here
const String iOSWidgetName = 'NewsWidgets';
const String androidWidgetName = 'NewsWidget'; // To here.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
void updateHeadline(NewsArticle newHeadline) { // Add from here
// Save the headline data to the widget
HomeWidget.saveWidgetData<String>('headline_title', newHeadline.title);
HomeWidget.saveWidgetData<String>(
'headline_description', newHeadline.description);
HomeWidget.updateWidget(
iOSName: iOSWidgetName,
androidName: androidWidgetName,
);
} // To here.
class _MyHomePageState extends State<MyHomePage> {
@override // Add from here
void initState() {
super.initState();
HomeWidget.setAppGroupId(appGroupId);
// Mock read in some data and update the headline
final newHeadline = getNewsStories()[0];
updateHeadline(newHeadline);
} // To here.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Top Stories'),
centerTitle: false,
titleTextStyle: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.black)),
body: ListView.separated(
separatorBuilder: (context, idx) {
return const Divider();
},
itemCount: getNewsStories().length,
itemBuilder: (context, idx) {
final article = getNewsStories()[idx];
return ListTile(
key: Key('$idx ${article.hashCode}'),
title: Text(article.title!),
subtitle: Text(article.description!),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return ArticleScreen(article: article);
},
),
);
},
);
},
));
}
}
Die Funktion updateHeadline
speichert die Schlüssel/Wert-Paare im lokalen Speicher Ihres Geräts. Der Schlüssel headline_title
enthält den Wert newHeadline.title
. Der Schlüssel headline_description
enthält den Wert von newHeadline.description
. Die Funktion benachrichtigt auch die native Plattform, dass neue Daten für die Startbildschirm-Widgets abgerufen und gerendert werden können.
„floatingActionButton“ ändern
Rufen Sie die Funktion updateHeadline
auf, wenn floatingActionButton
gedrückt wird, wie hier gezeigt:
lib/article_screen.dart
// New: import the updateHeadline function
import 'home_screen.dart';
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Updating home screen widget...'),
));
// New: call updateHeadline
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
...
Mit dieser Änderung werden die Details des Startbildschirm-Widgets aktualisiert, wenn ein Nutzer auf einer Artikelseite auf die Schaltfläche Überschrift aktualisieren tippt.
iOS-Code zur Anzeige der Artikeldaten aktualisieren
Verwenden Sie Xcode, um das Startbildschirm-Widget für iOS zu aktualisieren.
Öffnen Sie die Datei NewsWidgets.swift
in Xcode:
Konfigurieren Sie den TimelineEntry
.
Ersetzen Sie die Struktur SimpleEntry
durch den folgenden Code:
ios/NewsWidgets/NewsWidgets.swift
// The date and any data you want to pass into your app must conform to TimelineEntry
struct NewsArticleEntry: TimelineEntry {
let date: Date
let title: String
let description:String
}
Diese NewsArticleEntry
-Struktur definiert die eingehenden Daten, die bei der Aktualisierung an das Startbildschirm-Widget übergeben werden. Für den Typ TimelineEntry
ist ein Datumsparameter erforderlich.Weitere Informationen zum TimelineEntry
-Protokoll finden Sie in der TimelineEntry-Dokumentation von Apple.
Bearbeiten Sie die View
, mit der der Inhalt angezeigt wird.
Passen Sie das Startbildschirm-Widget so an, dass anstelle des Datums die Schlagzeile und die Beschreibung des Nachrichtenartikels angezeigt werden. Verwenden Sie die Ansicht Text
, um Text in SwiftUI anzuzeigen. Um Ansichten in SwiftUI übereinander zu stapeln, verwenden Sie die Ansicht VStack
.
Ersetzen Sie die generierte NewsWidgetEntryView
-Ansicht durch den folgenden Code:
ios/NewsWidgets/NewsWidgets.swift
//View that holds the contents of the widget
struct NewsWidgetsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text(entry.title)
Text(entry.description)
}
}
}
Bearbeite den Anbieter, um dem Startbildschirm-Widget mitzuteilen, wann und wie das Update durchgeführt werden soll.
Ersetzen Sie die vorhandene Provider
durch den folgenden Code. Ersetzen Sie dann <IHRE APP-GRUPPE> durch Ihre App-Gruppen-ID:
ios/NewsWidgets/NewsWidgets.swift
struct Provider: TimelineProvider {
// Placeholder is used as a placeholder when the widget is first displayed
func placeholder(in context: Context) -> NewsArticleEntry {
// Add some placeholder title and description, and get the current date
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description")
}
// Snapshot entry represents the current time and state
func getSnapshot(in context: Context, completion: @escaping (NewsArticleEntry) -> ()) {
let entry: NewsArticleEntry
if context.isPreview{
entry = placeholder(in: context)
}
else{
// Get the data from the user defaults to display
let userDefaults = UserDefaults(suiteName: <YOUR APP GROUP>)
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
entry = NewsArticleEntry(date: Date(), title: title, description: description)
}
completion(entry)
}
// getTimeline is called for the current and optionally future times to update the widget
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// This just uses the snapshot function you defined earlier
getSnapshot(in: context) { (entry) in
// atEnd policy tells widgetkit to request a new entry after the date has passed
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
}
Die Provider
im vorherigen Code entspricht einer TimelineProvider
. Für Provider
gibt es drei verschiedene Methoden:
- Die Methode
placeholder
generiert einen Platzhaltereintrag, wenn der Nutzer zum ersten Mal eine Vorschau des Startbildschirm-Widgets zeigt.
- Die Methode
getSnapshot
liest die Daten aus den Standardeinstellungen der Nutzer und generiert den Eintrag für die aktuelle Zeit. - Die Methode
getTimeline
gibt Zeitachseneinträge zurück. Das ist hilfreich, wenn du vorhersehbare Zeitpunkte für die Aktualisierung deiner Inhalte hast. In diesem Codelab wird mit der Funktion „getSnapshot“ der aktuelle Status abgerufen. Mit der Methode.atEnd
wird das Startbildschirm-Widget angewiesen, die Daten nach Ablauf der aktuellen Zeit zu aktualisieren.
NewsWidgets_Previews
auskommentieren
Die Verwendung von Vorschauen wird in diesem Codelab nicht behandelt. Weitere Informationen zur Vorschau von SwiftUI-Widgets auf dem Startbildschirm finden Sie in der Apple-Dokumentation zu Debugging-Widgets.
Speichern Sie alle Dateien und führen Sie die App und das Widget-Ziel noch einmal aus.
Führen Sie die Ziele noch einmal aus, um zu prüfen, ob die App und das Startbildschirm-Widget funktionieren.
- Wählen Sie das App-Schema in Xcode aus, um das App-Ziel auszuführen.
- Wählen Sie das Erweiterungsschema in Xcode aus, um das Erweiterungsziel auszuführen.
- Rufen Sie in der App eine Artikelseite auf.
- Klicken Sie auf die Schaltfläche, um den Anzeigentitel zu aktualisieren. Das Startbildschirm-Widget sollte auch die Überschrift aktualisieren.
Android-Code aktualisieren
Füge die XML-Datei des Startbildschirm-Widgets hinzu.
Aktualisieren Sie in Android Studio die im vorherigen Schritt generierten Dateien.Öffnen Sie die Datei res/layout/news_widget.xml
. Es definiert die Struktur und das Layout Ihres Startbildschirm-Widgets. Wählen Sie oben rechts Code aus und ersetzen Sie den Inhalt dieser Datei durch den folgenden Code:
android/app/res/layout/news_widget.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
</RelativeLayout>
Dieser XML-Code definiert zwei Textansichten, eine für die Artikelüberschrift und eine für die Artikelbeschreibung. In diesen Textansichten wird auch der Stil definiert. In diesem Codelab werden Sie immer wieder zu dieser Datei zurückkehren.
NewsWidget-Funktionalität aktualisieren
Öffnen Sie die Kotlin-Quellcodedatei NewsWidget.kt
. Diese Datei enthält eine generierte Klasse namens NewsWidget
, die die Klasse AppWidgetProvider
erweitert.
Die Klasse NewsWidget
enthält drei Methoden aus ihrer Basisklasse. Sie ändern die Methode onUpdate
. Android ruft diese Methode für Widgets in festen Intervallen auf.
Ersetzen Sie den Inhalt der Datei NewsWidget.kt
durch den folgenden Code:
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
// New import.
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
// Get reference to SharedPreferences
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
Wenn jetzt onUpdate
aufgerufen wird, ruft Android mithilfe der Methode the widgetData.getString()
die neuesten Werte aus dem lokalen Speicher ab und ruft dann setTextViewText
auf, um den auf dem Startbildschirm angezeigten Text zu ändern.
Updates testen
Teste die App, um zu prüfen, ob deine Startbildschirm-Widgets mit neuen Daten aktualisiert werden. Du kannst die Daten auf den Artikelseiten über die Schaltfläche Startbildschirm aktualisieren FloatingActionButton
aktualisieren. Ihr Startbildschirm-Widget sollte mit dem Titel des Artikels aktualisiert werden.
5. Benutzerdefinierte Schriftarten der Flutter App im iOS-Startbildschirm-Widget verwenden
Bisher haben Sie das Startbildschirm-Widget so konfiguriert, dass die von der Flutter App bereitgestellten Daten gelesen werden. Die Flutter App enthält eine benutzerdefinierte Schriftart, die Sie für das Startbildschirm-Widget verwenden können. Sie können die benutzerdefinierte Schriftart im Widget für den iOS-Startbildschirm verwenden. Die Verwendung benutzerdefinierter Schriftarten in Startbildschirm-Widgets ist auf Android-Geräten nicht verfügbar.
iOS-Code aktualisieren
Flutter speichert seine Assets im mainBundle der iOS-Apps. Über den Code des Startbildschirm-Widgets können Sie auf die Assets in diesem Set zugreifen.
Nehmen Sie in der Struktur NewsWidgetsEntryView in Ihrer Datei NewsWidgets.swift die folgenden Änderungen vor:
Erstellen Sie eine Hilfsfunktion, um den Pfad zum Flutter-Asset-Verzeichnis zu erhalten:
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Add the helper function.
var bundle: URL {
let bundle = Bundle.main
if bundle.bundleURL.pathExtension == "appex" {
// Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
var url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
url.append(component: "Frameworks/App.framework/flutter_assets")
return url
}
return bundle.bundleURL
}
...
}
Registrieren Sie die Schriftart mithilfe der URL Ihrer benutzerdefinierten Schriftartdatei.
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Register the font.
init(entry: Provider.Entry){
self.entry = entry
CTFontManagerRegisterFontsForURL(bundle.appending(path: "/fonts/Chewy-Regular.ttf") as CFURL, CTFontManagerScope.process, nil)
}
...
}
Die benutzerdefinierte Schriftart in der Textansicht für Anzeigentitel verwenden
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
var body: some View {
VStack {
// Update the following line.
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description)
}
}
...
}
Wenn Sie das Startbildschirm-Widget ausführen, wird jetzt die benutzerdefinierte Schriftart für die Überschrift verwendet, wie in der folgenden Abbildung dargestellt:
6. Flutter-Widgets als Bild rendern
In diesem Abschnitt zeigen Sie eine Grafik aus der Flutter-App als Startbildschirm-Widget an.
Dieses Widget bietet eine größere Herausforderung als der Text, den Sie auf dem Startbildschirm angezeigt haben. Es ist viel einfacher, das Flutter-Diagramm als Bild darzustellen, als es mit nativen UI-Komponenten neu zu erstellen.
Codieren Sie Ihr Startbildschirm-Widget so, dass Ihr Flutter-Diagramm als PNG-Datei gerendert wird. Dieses Bild kann im Startbildschirm-Widget angezeigt werden.
Dart-Code schreiben
Fügen Sie auf Dart-Seite die Methode renderFlutterWidget
aus dem Paket „home_widget“ hinzu. Diese Methode verwendet ein Widget, einen Dateinamen und einen Schlüssel. Sie gibt ein Bild des Flutter-Widgets zurück und speichert es in einem gemeinsamen Container. Geben Sie den Bildnamen im Code an und prüfen Sie, ob das Startbildschirm-Widget auf den Container zugreifen kann. Die key
speichert den vollständigen Dateipfad als String im lokalen Speicher des Geräts. So kann das Startbildschirm-Widget die Datei finden, wenn sich der Name im Dart-Code ändert.
In diesem Codelab stellt die Klasse LineChart
in der Datei lib/article_screen.dart
das Diagramm dar. Die zugehörige Build-Methode gibt einen CustomPainter zurück, mit dem dieses Diagramm auf den Bildschirm übertragen wird.
Öffnen Sie die Datei lib/article_screen.dart
, um dieses Feature zu implementieren. Importieren Sie das Paket „home_widget“. Ersetzen Sie als Nächstes den Code in der Klasse _ArticleScreenState
durch den folgenden Code:
lib/article_screen.dart
import 'package:flutter/material.dart';
// New: import the home_widget package.
import 'package:home_widget/home_widget.dart';
import 'home_screen.dart';
import 'news_data.dart';
...
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
String? imagePath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.article.title!),
),
// New: add this FloatingActionButton
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
const LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
body: ListView(
padding: const EdgeInsets.all(16.0),
children: [
Text(
widget.article.description!,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
const SizedBox(height: 20.0),
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
],
),
);
}
}
In diesem Beispiel werden drei Änderungen an der Klasse _ArticleScreenState
vorgenommen.
Erstellt einen GlobalKey
GlobalKey
ruft den Kontext des jeweiligen Widgets ab, der zum Abrufen der Größe dieses Widgets erforderlich ist .
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
...
}
Fügt „imagePath“ hinzu
Mit der Eigenschaft imagePath
wird die Position des Bilds gespeichert, an der das Flutter-Widget gerendert wird.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
// New: add this imagePath
String? imagePath;
...
}
Fügt den Schlüssel dem zu rendernden Widget hinzu
_globalKey
enthält das Flutter-Widget, das für das Bild gerendert wird. In diesem Fall ist das Flutter-Widget das Zentrum mit dem LineChart
.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
...
}
- Speichert das Widget als Bild
Die Methode renderFlutterWidget
wird aufgerufen, wenn der Nutzer auf floatingActionButton
klickt. Die Methode speichert die resultierende PNG-Datei als "Screenshot". in das Verzeichnis des freigegebenen Containers. Die Methode speichert auch den vollständigen Pfad zum Image als Dateinamenschlüssel im Gerätespeicher.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
...
}
iOS-Code aktualisieren
Bei iOS aktualisieren Sie den Code, um den Dateipfad aus dem Speicher abzurufen und die Datei mithilfe von SwiftUI als Bild anzuzeigen.
Öffnen Sie die Datei NewsWidgets.swift
und nehmen Sie folgende Änderungen vor:
Füge filename
und displaySize
zur Struktur NewsArticleEntry
hinzu.
Das Attribut filename
enthält den String, der den Pfad zur Bilddatei darstellt. Das Attribut displaySize
enthält die Größe des Startbildschirm-Widgets auf dem Gerät des Nutzers. Die Größe des Startbildschirm-Widgets stammt von context
.
ios/NewsWidgets/NewsWidgets.swift
struct NewsArticleEntry: TimelineEntry {
...
// New: add the filename and displaySize.
let filename: String
let displaySize: CGSize
}
Die Funktion placeholder
aktualisieren
Fügen Sie die Platzhalter filename
und displaySize
ein.
ios/NewsWidgets/NewsWidgets.swift
func placeholder(in context: Context) -> NewsArticleEntry {
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description", filename: "No screenshot available", displaySize: context.displaySize)
}
Dateinamen aus userDefaults
in getSnapshot abrufen
Dadurch wird die Variable filename
auf den Wert filename
im userDefaults
-Speicher gesetzt, wenn das Startbildschirm-Widget aktualisiert wird.
ios/NewsWidgets/NewsWidgets.swift
func getSnapshot(
...
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
// New: get fileName from key/value store
let filename = userDefaults?.string(forKey: "filename") ?? "No screenshot available"
...
)
ChartImage erstellen, das das Bild aus einem Pfad anzeigt
In der Ansicht ChartImage
wird ein Bild aus den Inhalten der auf Dart-Seite generierten Datei erstellt. Hier legen Sie die Größe auf 50% des Frames fest.
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: create the ChartImage view
var ChartImage: some View {
if let uiImage = UIImage(contentsOfFile: entry.filename) {
let image = Image(uiImage: uiImage)
.resizable()
.frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center)
return AnyView(image)
}
print("The image file could not be loaded")
return AnyView(EmptyView())
}
...
}
ChartImage im Text von NewsWidgetsEntryView verwenden
Fügen Sie die ChartImage-Ansicht zum Hauptteil von NewsWidgetsEntryView hinzu, um das ChartImage im Startbildschirm-Widget anzuzeigen.
ios/NewsWidgets/NewsWidgets.swift
VStack {
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description).font(.system(size: 12)).padding(10)
// New: add the ChartImage to the NewsWidgetEntryView
ChartImage
}
Änderungen testen
Um die Änderungen zu testen, führen Sie sowohl das Ziel der Flutter-App (Ausführer) als auch das Erweiterungsziel aus Xcode noch einmal aus. Wenn Sie sich das Bild ansehen möchten, rufen Sie eine der Artikelseiten in der App auf und drücken Sie die Taste, um das Startbildschirm-Widget zu aktualisieren.
Android-Code aktualisieren
Der Android-Code funktioniert genauso wie der iOS-Code.
- Öffnen Sie die Datei
android/app/res/layout/news_widget.xml
. Es enthält die UI-Elemente Ihres Startbildschirm-Widgets. Ersetzen Sie den Inhalt durch den folgenden Code:
android/app/res/layout/news_widget.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
<!--New: add this image view -->
<ImageView
android:id="@+id/widget_image"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="@+id/headline_description"
android:layout_alignBottom="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="-134dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@android:color/white"
android:scaleType="fitCenter"
android:src="@android:drawable/star_big_on"
android:visibility="visible"
tools:visibility="visible" />
</RelativeLayout>
Mit diesem neuen Code wird dem Startbildschirm-Widget ein Bild hinzugefügt, das vorerst ein allgemeines Sternsymbol anzeigt. Ersetzen Sie dieses Sternsymbol durch das Bild, das Sie im Dart-Code gespeichert haben.
- Öffnen Sie die Datei
NewsWidget.kt
. Ersetzen Sie den Inhalt durch den folgenden Code:
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.RemoteViews
import java.io.File
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
// New: Add the section below
// Get chart image and put it in the widget, if it exists
val imageName = widgetData.getString("filename", null)
val imageFile = File(imageName)
val imageExists = imageFile.exists()
if (imageExists) {
val myBitmap: Bitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
setImageViewBitmap(R.id.widget_image, myBitmap)
} else {
println("image not found!, looked @: ${imageName}")
}
// End new code
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
Dieser Dart-Code speichert einen Screenshot mit dem filename
-Schlüssel im lokalen Speicher. Außerdem ruft sie den vollständigen Pfad des Bildes ab und erstellt daraus ein File
-Objekt. Wenn das Bild vorhanden ist, ersetzt der Dart-Code das Bild im Startbildschirm-Widget durch das neue Bild.
- Aktualisiere deine App und rufe einen Artikelbildschirm auf. Tippen Sie auf Startbildschirm aktualisieren. Das Startbildschirm-Widget zeigt das Diagramm an.
7. Nächste Schritte
Glückwunsch!
Herzlichen Glückwunsch! Sie haben erfolgreich Startbildschirm-Widgets für Ihre Flutter-Apps für iOS und Android erstellt.
Links zu Inhalten in Ihrer Flutter-App
Möglicherweise möchten Sie den Nutzer auf eine bestimmte Seite in Ihrer App weiterleiten, je nachdem, auf welche Seite er klickt. In der Nachrichten-App aus diesem Codelab möchten Sie beispielsweise, dass der Nutzer den Nachrichtenartikel für die angezeigte Schlagzeile sieht.
Diese Funktion wird in diesem Codelab nicht behandelt. Sie finden Beispiele für die Verwendung eines Streams, der vom Paket „home_widget“ bereitgestellt wird, um App-Starts von Startbildschirm-Widgets zu identifizieren und Nachrichten über das Startbildschirm-Widget über die URL zu senden. Weitere Informationen finden Sie in der Dokumentation zu Deeplinks unter docs.flutter.dev.
Widget im Hintergrund aktualisieren
In diesem Codelab haben Sie über eine Schaltfläche eine Aktualisierung des Startbildschirm-Widgets ausgelöst. Obwohl dies für Tests sinnvoll ist, sollte im Produktionscode Ihre App das Startbildschirm-Widget im Hintergrund aktualisieren. Mit dem Workmanager-Plug-in können Sie Hintergrundaufgaben erstellen, um Ressourcen zu aktualisieren, die das Startbildschirm-Widget benötigt. Weitere Informationen finden Sie im Abschnitt Hintergrundaktualisierung des Pakets „home_widget“.
Bei iOS kann das Startbildschirm-Widget auch eine Netzwerkanfrage zum Aktualisieren der Benutzeroberfläche senden. Über die Zeitachse können Sie die Bedingungen oder die Häufigkeit dieser Anfrage steuern. Weitere Informationen zur Verwendung der Zeitachse finden Sie im Apple-Artikel „Widget up to date“ („Widget auf dem neuesten Stand halten“). Dokumentation.