1. Introduzione
Che cosa sono i widget?
Per gli sviluppatori Flutter, la definizione comune di widget si riferisce ai componenti UI creati utilizzando il framework Flutter. Nel contesto di questo codelab, un widget si riferisce a una mini versione di un'app che fornisce una visualizzazione delle informazioni dell'app senza aprirla. Su Android, i widget si trovano nella schermata Home. Su iOS, possono essere aggiunti alla schermata Home, alla schermata di blocco o alla visualizzazione Oggi.

Quanto può essere complesso un widget?
La maggior parte dei widget della schermata Home è semplice. Potrebbero contenere testo di base, grafica semplice o, su Android, controlli di base. Sia Android che iOS limitano i componenti e le funzionalità dell'interfaccia utente che puoi utilizzare.

Creare l'interfaccia utente per i widget
A causa di queste limitazioni della UI, non puoi disegnare direttamente la UI di un widget della schermata Home utilizzando il framework Flutter. Puoi invece aggiungere widget creati con framework della piattaforma come Jetpack Compose o SwiftUI alla tua app Flutter. Questo codelab illustra esempi di condivisione di risorse tra l'app e i widget per evitare di riscrivere UI complesse.
Cosa creerai
In questo codelab, creerai widget della schermata Home sia su Android che su iOS per una semplice app Flutter, utilizzando il pacchetto home_widget, che consente agli utenti di leggere articoli. I widget:
- Mostra i dati della tua app Flutter.
- Visualizza il testo utilizzando gli asset dei caratteri condivisi dall'app Flutter.
- Mostra un'immagine di un widget Flutter sottoposto a rendering.

Questa app Flutter include due schermate (o route):
- Il primo mostra un elenco di articoli di notizie con titoli e descrizioni.
- La seconda mostra l'articolo completo con un grafico creato utilizzando
CustomPaint.
.

Cosa imparerai
- Come creare widget della schermata Home su iOS e Android.
- Come utilizzare il pacchetto home_widget per condividere i dati tra il widget della schermata Home e l'app Flutter.
- Come ridurre la quantità di codice da riscrivere.
- Come aggiornare il widget della schermata Home dall'app Flutter.
2. Configurazione dell'ambiente di sviluppo
Per entrambe le piattaforme, sono necessari l'SDK Flutter e un IDE. Puoi utilizzare il tuo IDE preferito per lavorare con Flutter. Può trattarsi di Visual Studio Code con le estensioni Dart Code e Flutter oppure di Android Studio o IntelliJ con i plug-in Flutter e Dart installati.
Per creare il widget della schermata Home di iOS:
- Puoi eseguire questo codelab su un dispositivo iOS fisico o sul simulatore iOS.
- Devi configurare un sistema macOS con l'IDE Xcode. Viene installato il compilatore necessario per creare la versione iOS della tua app.
Per creare il widget della schermata Home di Android:
- Puoi eseguire questo codelab su un dispositivo Android fisico o sull'emulatore Android.
- Devi configurare il sistema di sviluppo con Android Studio. Viene installato il compilatore necessario per creare la versione Android dell'app.
Ottenere il codice di avvio
Scaricare la versione iniziale del progetto da GitHub
Dalla riga di comando, clona il repository GitHub in una directory flutter-codelabs:
$ git clone https://github.com/flutter/codelabs.git flutter-codelabs
Dopo aver clonato il repository, puoi trovare il codice per questo codelab nella directory flutter-codelabs/homescreen_codelab. Questa directory contiene il codice del progetto completato per ogni passaggio del codelab.
Apri l'app di avvio
Apri la directory flutter-codelabs/homescreen_codelab/step_03 nell'IDE che preferisci.
Installare i pacchetti
Tutti i pacchetti richiesti sono stati aggiunti al file pubspec.yaml del progetto. Per recuperare le dipendenze del progetto, esegui questo comando:
$ flutter pub get
3. Aggiungere un widget di base alla schermata Home
Innanzitutto, aggiungi il widget della schermata Home utilizzando gli strumenti della piattaforma nativa.
Creare un widget di base per la schermata Home di iOS
L'aggiunta di un'estensione per app alla tua app Flutter per iOS è simile all'aggiunta di un'estensione per app a un'app SwiftUI o UIKit:
- Esegui
open ios/Runner.xcworkspacein una finestra del terminale dalla directory del progetto Flutter. In alternativa, fai clic con il tasto destro del mouse sulla cartella ios in VSCode e seleziona Open in Xcode (Apri in Xcode). Si aprirà il workspace Xcode predefinito nel progetto Flutter. - Seleziona File → Nuovo → Target dal menu. In questo modo, viene aggiunto un nuovo target al progetto.
- Viene visualizzato un elenco di modelli. Seleziona Estensione widget.
- Digita "NewsWidgets" nella casella Nome prodotto per questo widget. Deseleziona le caselle di controllo Includi attività live e Includi intent di configurazione.
Esaminare il codice campione
Quando aggiungi un nuovo target, Xcode genera un codice di esempio in base al modello selezionato. Per saperne di più sul codice generato e su WidgetKit, consulta la documentazione di Apple sulle estensioni delle app .
Eseguire il debug e testare il widget di esempio
- Innanzitutto, aggiorna la configurazione dell'app Flutter. Devi farlo quando aggiungi nuovi pacchetti nella tua app Flutter e prevedi di eseguire un target nel progetto da Xcode. Per aggiornare la configurazione dell'app, esegui questo comando nella directory dell'app Flutter:
$ flutter build ios --config-only
- Fai clic su Runner per visualizzare un elenco di target. Seleziona il target del widget appena creato, NewsWidgets, e fai clic su Esegui. Esegui il target del widget da Xcode quando modifichi il codice del widget iOS.

- Il simulatore o lo schermo del dispositivo dovrebbe mostrare un widget di base della schermata Home. Se non lo vedi, puoi aggiungerlo alla schermata. Fai clic e tieni premuto sulla schermata Home, poi fai clic su + nell'angolo in alto a sinistra.

- Cerca il nome dell'app. Per questo codelab, cerca "Homescreen Widgets" (Widget della schermata Home).

- Una volta aggiunto il widget della schermata Home, dovrebbe essere visualizzato un testo semplice che indica l'ora.
Creare un widget Android di base
- Per aggiungere un widget della schermata Home in Android, apri il file di build del progetto in Android Studio. Puoi trovare questo file in android/build.gradle. In alternativa, fai clic con il tasto destro del mouse sulla cartella android in VSCode e seleziona Open in Android Studio (Apri in Android Studio).
- Dopo la creazione del progetto, individua la directory dell'app nell'angolo in alto a sinistra. Aggiungi il nuovo widget della schermata Home a questa directory. Fai clic con il tasto destro del mouse sulla directory, seleziona Nuovo > Widget > Widget app.

- Android Studio mostra un nuovo modulo. Aggiungi le informazioni di base sul widget della schermata Home, tra cui nome della classe, posizionamento, dimensioni e lingua di origine.
Per questo codelab, imposta i seguenti valori:
- Casella Class Name (Nome classe) in NewsWidget
- Larghezza minima (celle) a 3
- Altezza minima (celle) a 3
Esaminare il codice campione
Quando invii il modulo, Android Studio crea e aggiorna diversi file. Le modifiche pertinenti per questo codelab sono elencate nella tabella seguente
Azione | File di destinazione | Cambia |
Aggiorna |
| Aggiunge un nuovo ricevitore che registra NewsWidget. |
Crea |
| Definisce la UI del widget della schermata Home. |
Crea |
| Definisce la configurazione del widget della schermata Home. Puoi modificare le dimensioni o il nome del widget in questo file. |
Crea |
| Contiene il codice Kotlin per aggiungere funzionalità al widget della schermata Home. |
Puoi trovare maggiori dettagli su questi file in questo codelab.
Eseguire il debug e testare il widget di esempio
Ora esegui l'applicazione e visualizza il widget della schermata Home. Dopo aver creato l'app, vai alla schermata di selezione delle applicazioni del tuo dispositivo Android e tieni premuta l'icona di questo progetto Flutter. Seleziona Widget dal menu popup.

Il dispositivo Android o l'emulatore mostra il widget della schermata Home predefinito per Android.
4. Inviare dati dall'app Flutter al widget della schermata Home
Puoi personalizzare il widget di base della schermata Home che hai creato. Aggiorna il widget della schermata Home per visualizzare un titolo e un riepilogo di un articolo di notizie. Il seguente screenshot mostra un esempio del widget della schermata Home che visualizza un titolo e un riepilogo.

Per trasferire dati tra l'app e il widget della schermata Home, devi scrivere codice Dart e nativo. Questa sezione suddivide il processo in tre parti:
- Scrivere codice Dart nell'app Flutter che può essere utilizzato sia da Android che da iOS
- Aggiungere funzionalità iOS native
- Aggiungere funzionalità Android native
Utilizzo dei gruppi di app per iOS
Per condividere dati tra un'app principale iOS e un'estensione widget, entrambi i target devono appartenere allo stesso gruppo di app. Per saperne di più sui gruppi di app, consulta la documentazione di Apple sui gruppi di app.
Aggiorna l'identificatore bundle:
In Xcode, vai alle impostazioni del target. Nella scheda Signing & Capabilities (Firma e funzionalità), verifica che siano impostati il team e l'identificatore bundle.
Aggiungi il gruppo di app sia al target Runner sia al target NewsWidgetExtension in Xcode:
Seleziona + Funzionalità -> Gruppi di app e aggiungi un nuovo gruppo di app. Ripeti l'operazione sia per il target Runner (app principale) sia per il target widget.

Aggiungere il codice Dart
Le app iOS e Android possono condividere i dati con un'app Flutter in diversi modi.Per comunicare con queste app, utilizza l'archivio locale key/value del dispositivo. iOS chiama questo archivio UserDefaults, mentre Android lo chiama SharedPreferences. Il pacchetto home_widget esegue il wrapping di queste API per semplificare il salvataggio dei dati su entrambe le piattaforme e consente ai widget della schermata Home di estrarre i dati aggiornati.

I dati del titolo e della descrizione provengono dal file news_data.dart. Questo file contiene dati fittizi e una classe di dati NewsArticle.
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,
});
}
Aggiorna i valori del titolo e della descrizione
Per aggiungere la funzionalità di aggiornamento del widget della schermata Home dalla tua app Flutter, vai al file lib/home_screen.dart. Sostituisci i contenuti del file con il seguente codice. Poi, sostituisci <YOUR APP GROUP> con l'identificatore del tuo gruppo di app.
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);
},
),
);
},
);
},
));
}
}
La funzione updateHeadline salva le coppie chiave/valore nella memoria locale del dispositivo. La chiave headline_title contiene il valore newHeadline.title. La chiave headline_description contiene il valore di newHeadline.description. La funzione comunica inoltre alla piattaforma nativa che è possibile recuperare e visualizzare nuovi dati per i widget della schermata Home.
Modificare floatingActionButton
Chiama la funzione updateHeadline quando viene premuto floatingActionButton come mostrato:
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'),
),
...
Con questa modifica, quando un utente preme il pulsante Aggiorna titolo dalla pagina di un articolo, i dettagli del widget della schermata Home vengono aggiornati.
Aggiorna il codice iOS per visualizzare i dati dell'articolo
Per aggiornare il widget della schermata Home per iOS, utilizza Xcode.
Apri il file NewsWidgets.swift in Xcode:
Configura TimelineEntry.
Sostituisci la struttura SimpleEntry con il seguente codice:
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
}
Questa struttura NewsArticleEntry definisce i dati in arrivo da passare al widget della schermata Home quando viene aggiornato. Il tipo TimelineEntry richiede un parametro data.Per scoprire di più sul protocollo TimelineEntry, consulta la documentazione di Apple su TimelineEntry.
Modifica il View che mostra i contenuti
Modifica il widget della schermata Home per visualizzare il titolo e la descrizione dell'articolo di notizie anziché la data. Per visualizzare il testo in SwiftUI, utilizza la visualizzazione Text. Per impilare le visualizzazioni una sopra l'altra in SwiftUI, utilizza la visualizzazione VStack.
Sostituisci la visualizzazione NewsWidgetEntryView generata con il seguente codice:
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)
}
}
}
Modifica il fornitore per indicare al widget della schermata Home quando e come eseguire l'aggiornamento
Sostituisci il codice Provider esistente con il seguente. Poi, sostituisci l'identificatore del gruppo di app a <YOUR APP GROUP>:
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)
}
}
}
Provider nel codice precedente è conforme a un TimelineProvider. Provider ha tre metodi diversi:
- Il metodo
placeholdergenera una voce segnaposto quando l'utente visualizza per la prima volta l'anteprima del widget della schermata Home.

- Il metodo
getSnapshotlegge i dati dalle impostazioni predefinite dell'utente e genera la voce per l'ora corrente. - Il metodo
getTimelinerestituisce le voci della cronologia. Questo è utile quando hai punti temporali prevedibili per aggiornare i tuoi contenuti. Questo codelab utilizza la funzione getSnapshot per ottenere lo stato attuale. Il metodo.atEndindica al widget della schermata Home di aggiornare i dati dopo che è trascorsa l'ora corrente.
Commenta NewsWidgets_Previews
L'utilizzo delle anteprime non rientra nell'ambito di questo codelab. Per ulteriori dettagli sull'anteprima dei widget della schermata Home di SwiftUI, consulta la documentazione di Apple sul debug dei widget.
Salva tutti i file ed esegui di nuovo il target dell'app e del widget.
Esegui di nuovo gli intent per verificare che l'app e il widget della schermata Home funzionino.
- Seleziona lo schema dell'app in Xcode per eseguire il target dell'app.
- Seleziona lo schema dell'estensione in Xcode per eseguire il target dell'estensione.
- Vai alla pagina di un articolo nell'app.
- Fai clic sul pulsante per aggiornare il titolo. Anche il widget della schermata Home dovrebbe aggiornare il titolo.
Aggiornare il codice Android
Aggiungi il file XML del widget della schermata Home.
In Android Studio, aggiorna i file generati nel passaggio precedente.Apri il file res/layout/news_widget.xml. Definisce la struttura e il layout del widget della schermata Home. Seleziona Codice nell'angolo in alto a destra e sostituisci i contenuti del file con il seguente codice:
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>
Questo XML definisce due visualizzazioni di testo, una per il titolo dell'articolo e l'altra per la descrizione dell'articolo. Queste visualizzazioni di testo definiscono anche lo stile. Tornerai a questo file durante tutto il codelab.
Aggiornamento della funzionalità del widget Notizie
Apri il file di codice sorgente Kotlin NewsWidget.kt. Questo file contiene una classe generata denominata NewsWidget che estende la classe AppWidgetProvider.
La classe NewsWidget contiene tre metodi della superclasse. Modificherai il metodo onUpdate. Android chiama questo metodo per i widget a intervalli fissi.
Sostituisci i contenuti del file NewsWidget.kt con il seguente codice:
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)
}
}
}
Ora, quando viene chiamato onUpdate, Android recupera i valori più recenti dall'archivio locale utilizzando il metodo the widgetData.getString(), quindi chiama setTextViewText per modificare il testo visualizzato nel widget della schermata Home.
Testare gli aggiornamenti
Testa l'app per assicurarti che i widget della schermata Home si aggiornino con i nuovi dati. Per aggiornare i dati, utilizza l'opzione Aggiorna schermata Home FloatingActionButton nelle pagine degli articoli. Il widget della schermata Home dovrebbe aggiornarsi con il titolo dell'articolo.

5. Utilizzare i caratteri personalizzati dell'app Flutter nel widget della schermata Home di iOS
Finora, hai configurato il widget della schermata Home per leggere i dati forniti dall'app Flutter. L'app Flutter include un carattere personalizzato che potresti voler utilizzare nel widget della schermata Home. Puoi utilizzare il carattere personalizzato nel widget della schermata Home di iOS. L'utilizzo di caratteri personalizzati nei widget della schermata Home non è disponibile su Android.
Aggiorna il codice iOS
Flutter archivia i suoi asset nel mainBundle delle applicazioni iOS. Puoi accedere agli asset in questo bundle dal codice del widget della schermata Home.
Nella struct NewsWidgetsEntryView del file NewsWidgets.swift, apporta le seguenti modifiche
Crea una funzione helper per ottenere il percorso della directory degli asset Flutter:
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
}
...
}
Registra il carattere utilizzando l'URL del file del carattere personalizzato.
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)
}
...
}
Aggiorna la visualizzazione Testo del titolo per utilizzare il carattere personalizzato.
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)
}
}
...
}
Quando esegui il widget della schermata Home, ora utilizza il carattere personalizzato per il titolo, come mostrato nell'immagine seguente:

6. Rendering dei widget Flutter come immagine
In questa sezione, visualizzerai un grafico della tua app Flutter come widget della schermata Home.
Questo widget offre una sfida maggiore rispetto al testo visualizzato nella schermata Home. È molto più semplice visualizzare il grafico Flutter come immagine piuttosto che provare a ricrearlo utilizzando i componenti dell'interfaccia utente nativa.
Codifica il widget della schermata Home per eseguire il rendering del grafico Flutter come file PNG. Il widget della schermata Home può visualizzare questa immagine.
Scrivi il codice Dart
Sul lato Dart, aggiungi il metodo renderFlutterWidget dal pacchetto home_widget. Questo metodo accetta un widget, un nome file e una chiave. Restituisce un'immagine del widget Flutter e la salva in un contenitore condiviso. Fornisci il nome dell'immagine nel codice e assicurati che il widget della schermata Home possa accedere al contenitore. key salva il percorso completo del file come stringa nello spazio di archiviazione locale del dispositivo. In questo modo, il widget della schermata Home può trovare il file se il nome cambia nel codice Dart.
Per questo codelab, la classe LineChart nel file lib/article_screen.dart rappresenta il grafico. Il suo metodo di creazione restituisce un CustomPainter che disegna questo grafico sullo schermo.
Per implementare questa funzionalità, apri il file lib/article_screen.dart. Importa il pacchetto home_widget. Poi, sostituisci il codice nella classe _ArticleScreenState con il seguente codice:
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!),
],
),
);
}
}
Questo esempio apporta tre modifiche alla classe _ArticleScreenState.
Crea una GlobalKey
GlobalKey ottiene il contesto del widget specifico, necessario per ottenere le dimensioni del widget .
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
...
}
Aggiunge imagePath
La proprietà imagePath memorizza la posizione dell'immagine in cui viene eseguito il rendering del widget Flutter.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
// New: add this imagePath
String? imagePath;
...
}
Aggiunge la chiave al widget da visualizzare
_globalKey contiene il widget Flutter sottoposto a rendering nell'immagine. In questo caso, il widget Flutter è Center, che contiene LineChart.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
...
}
- Salva il widget come immagine
Il metodo renderFlutterWidget viene chiamato quando l'utente fa clic su floatingActionButton. Il metodo salva il file PNG risultante come "screenshot" nella directory del contenitore condiviso. Il metodo salva anche il percorso completo dell'immagine come chiave del nome file nello spazio di archiviazione del dispositivo.
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);
},
...
}
Aggiornare il codice iOS
Per iOS, aggiorna il codice per ottenere il percorso del file dallo spazio di archiviazione e visualizzare il file come immagine utilizzando SwiftUI.
Apri il file NewsWidgets.swift per apportare le seguenti modifiche:
Aggiungi filename e displaySize a NewsArticleEntry struct
La proprietà filename contiene la stringa che rappresenta il percorso del file immagine. La proprietà displaySize contiene le dimensioni del widget della schermata Home sul dispositivo dell'utente. Le dimensioni del widget della schermata Home derivano da context.
ios/NewsWidgets/NewsWidgets.swift
struct NewsArticleEntry: TimelineEntry {
...
// New: add the filename and displaySize.
let filename: String
let displaySize: CGSize
}
Aggiorna la funzione placeholder
Includi un segnaposto filename e displaySize.
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)
}
Ottieni il nome file da userDefaults in getSnapshot
In questo modo, la variabile filename viene impostata sul valore filename nell'archivio userDefaults quando il widget della schermata Home viene aggiornato.
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"
...
)
Crea ChartImage che visualizza l'immagine da un percorso
La visualizzazione ChartImage crea un'immagine dai contenuti del file generato sul lato Dart. Qui imposti le dimensioni al 50% del frame.
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())
}
...
}
Utilizza ChartImage nel corpo di NewsWidgetsEntryView
Aggiungi la visualizzazione ChartImage al corpo di NewsWidgetsEntryView per visualizzare ChartImage nel widget della schermata Home.
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
}
Testare le modifiche
Per testare le modifiche, esegui di nuovo sia la destinazione dell'app Flutter (Runner) sia la destinazione dell'estensione da Xcode. Per visualizzare l'immagine, vai a una delle pagine degli articoli nell'app e premi il pulsante per aggiornare il widget della schermata Home.

Aggiornare il codice Android
Il codice Android funziona come il codice iOS.
- Apri il file
android/app/res/layout/news_widget.xml. Contiene gli elementi dell'interfaccia utente del widget della schermata Home. Sostituisci i contenuti con il seguente codice:
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>
Questo nuovo codice aggiunge un'immagine al widget della schermata Home, che (per ora) mostra un'icona a forma di stella generica. Sostituisci questa icona a forma di stella con l'immagine che hai salvato nel codice Dart.
- Apri il file
NewsWidget.kt. Sostituisci i contenuti con il seguente codice:
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)
}
}
}
Questo codice Dart salva uno screenshot nella memoria locale con la chiave filename. Recupera anche il percorso completo dell'immagine e crea un oggetto File. Se l'immagine esiste, il codice Dart sostituisce l'immagine nel widget della schermata Home con la nuova immagine.
- Ricarica l'app e vai alla schermata di un articolo. Premi Aggiorna schermata Home. Il widget della schermata Home mostra il grafico.
7. Passaggi successivi
Complimenti!
Congratulazioni, sei riuscito a creare widget della schermata Home per le tue app Flutter per iOS e Android.
Collegamento a contenuti nella tua app Flutter
A seconda di dove fa clic l'utente, potresti volerlo indirizzare a una pagina specifica della tua app. Ad esempio, nell'app di notizie di questo codelab, potresti voler mostrare all'utente l'articolo di notizie relativo al titolo visualizzato.
Questa funzionalità non rientra nell'ambito di questo codelab. Puoi trovare esempi di utilizzo di uno stream fornito dal pacchetto home_widget per identificare gli avvii di app dai widget della schermata Home e inviare messaggi dal widget della schermata Home tramite l'URL. Per saperne di più, consulta la documentazione sui deep link su docs.flutter.dev.
Aggiornamento del widget in background
In questo codelab, hai attivato un aggiornamento del widget della schermata Home utilizzando un pulsante. Anche se questo è ragionevole per i test, nel codice di produzione potresti voler che la tua app aggiorni il widget della schermata Home in background. Puoi utilizzare il plug-in workmanager per creare attività in background per aggiornare le risorse necessarie al widget della schermata Home. Per saperne di più, consulta la sezione Aggiornamento in background nel pacchetto home_widget.
Per iOS, puoi anche fare in modo che il widget della schermata Home invii una richiesta di rete per aggiornare la sua UI. Per controllare le condizioni o la frequenza di questa richiesta, utilizza la cronologia. Per scoprire di più sull'utilizzo della sequenza temporale, consulta la documentazione di Apple "Mantenere aggiornato un widget" .