iOS14 Widgets con WidgetKit

      Nessun commento su iOS14 Widgets con WidgetKit

Al keynote di WWDC20, Apple ha annunciato iOS 14 con nuove straordinarie funzionalità, tra le tante troviamo i Widget nella schermata principale.

Oggi scopriremo come aggiungere widget alla tua app!

Innanzitutto, dovrai scaricare alcuni software beta. Tieni presente che si tratta di beta sviluppatore e avrai bisogno di un account sviluppatore Apple.

ASSICURARSI DI AVERE UN BACKUP DEI DATI PRIMA DI INSTALLARE QUALSIASI SOFTWARE BETA

Tutto ciò che serve è Xcode 12, oppure se vuoi anche la nuova UI di xcode and macOS Big Sur.

Configura il tuo progetto

Puoi usare un progetto Xcode esistente o crearne uno nuovo. Tutto ciò che ti serve ora è andare su File -> New -> Target

Quindi selezionare Widget Extension da lì

widget extension

E ora dai un nome alla tua estensione Widget (nel nostro caso MyWidget) e assicurati che Include Configuration Intent sia selezionato.

Ti verrà quindi chiesto di attivare un nuovo schema. Seleziona Attiva.

Ora vedrai una nuova cartella nel tuo progetto con il nome del tuo widget.

Apri MyWidget.swift ed elimina tutto al suo interno tranne le istruzioni di import.

Creare un widget

Ora siamo pronti per iniziare a creare il nostro widget! Crea una struct chiamata MyWidget conforme al protocollo Widget e aggiungi il wrapper di proprietà @main come in SwiftUI, Xcode dovrebbe darti il completamento automatico.

[code lang=”swift”]
@main
struct MyWidget: Widget {
public var body: some WidgetConfiguration {

}
}
[/code]

In questo tutorial vedremo solo i widget statici che possono mostrare solo contenuti specifici, come il widget fitness:

widget fitness

Esiste anche un altro tipo di widget che utilizzano le interazioni dell’utente nell’app per fornire dati più personalizzati, chiamati widget Intent. Non li toccheremo in questo tutorial.

Per creare un widget statico dobbiamo specificare la configurazione del widget nel corpo di MyWidget. Questo è ciò di cui avremo bisogno per creare una configurazione statica:

  • kind è una stringa personalizzata che identificherà il tuo widget. Es .: “com.example.mywidget”
  • provider è un oggetto che determinerà quando aggiornare il tuo widget, quindi è sempre aggiornato.
  • placeholder è una vista che mostra una rappresentazione generica del widget. WidgetKit mostra questa vista sulla schermata di blocco e prima di eseguire il rendering del contenuto del widget.
  • content è una vista che renderà il widget. In questo tutorial useremo SwiftUI per il rendering del widget.

Nota: TimelineProvider e TimelineEntry sono protocolli, quindi è necessario creare oggetti conformi a questi.

Widget Entry

Inizialmente creeremo un oggetto WidgetEntry conforme a TimelineEntry. TimelineEntry richiede che i tipi conformi abbiano la variabile data.

[code lang=”swift”]
struct WidgetEntry: TimelineEntry {
var date: Date
var value: Double
}
[/code]

Widget Provider

Quindi creeremo una struct provider conforme a TimelineProvider. TimelineProvider è anche esso un protocollo, quindi dobbiamo conformare il nostro Provider a un paio di metodi e anche creare un typealias.

[code lang=”swift”]
struct Provider: TimelineProvider {
typealias Entry = WidgetEntry

func snapshot(with context: Context, completion: @escaping (WidgetEntry) ->; ()) {
}
func timeline(with context: Context, completion: @escaping (Timeline<WidgetEntry>) -> ()) {
}
}
[/code]

Ora dobbiamo inserire un po’ di codice nella funzione snapshot e timeline.

Snapshot

Il metodo Snapshot mostra lo stato corrente del widget. Ad esempio, se effettuiamo una richiesta di rete e riceviamo dati da essa che sarebbe un’istantanea.

Dobbiamo fare in modo che la voce del widget presenti un esempio di dati quando è in modalità anteprima, quindi dobbiamo verificare se il contesto corrente è in anteprima. Dopo aver creato una voce, dobbiamo passare questa voce al completamento. (WidgetData è una struttura contenente proprietà statiche come currentValue)

[code lang=”swift”]
func snapshot(with context: Context, completion: @escaping (Entry) -> ()) {
let date = Date()
let entry: WidgetEntry
if context.isPreview {
entry = WidgetEntry(date: date, value: 0.75)
} else {
entry = WidgetEntry(date: date, value: WidgetData.currentValue)
}
completion(entry)
}
[/code]


 

Timeline

Il metodo della sequenza timeline è responsabile della presentazione di dati aggiornati. Ai fini di questo tutorial creeremo una voce che invierà la data corrente alla sequenza temporale.

[code lang=”swift”]
func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
[/code]

“Che cosa significa la policy .atEnd?”

TimelineReloadPolicy descrive quando dovremmo aggiornare il nostro widget. .atEnd significa che verrà aggiornato quando passerà la data delle voci precedenti. Inoltre, non si verifica mai un caso in cui il widget si aggiorna solo quando viene presentato il widget, quindi quando l’utente sblocca il proprio telefono o scorre attraverso la schermata principale.

Configurazione

Dopo aver fatto tutto ciò, ora puoi procedere per completare la configurazione statica.

Ogni volta che viene passata una nuova voce nella sequenza temporale, verrà chiamata la voce del blocco.

[code lang=”swift”]
@main
struct MyWidget: Widget {
public var body: some WidgetConfiguration {
StaticConfiguration(
kind: "com.example.mywidget",
provider: Provider(),
placeholder: Text("Placeholder Text")) { entry in
}
}
}
[/code]

Questo è ciò che dovresti trovare nel corpo di Widget.

Creare una view

Ora non resta che creare una view SwiftUI che presenterà i dati. Questa è una view semplice che ho creato. Ha una proprietà entry che ti permette di cambiare lo stato del widget che dipende dai sui suoi dati.

[code lang=”swift”]
struct WidgetView: View {
var entry: WidgetEntry
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.black)
Text("Il valore corrente è \(entry.value)%")
.foregroundColor(.red)
.font(.largeTitle)
.multilineTextAlignment(.center)
.padding()
}
}
}
[/code]

Passare una view al widget

Crea un’istanza della tua vista nel blocco nella nostra configurazione statica.

[code lang=”swift”]
@main
struct MyWidget: Widget {
public var body: some WidgetConfiguration {
StaticConfiguration(
kind: "com.example.mywidget",
provider: Provider(),
placeholder: Text("Placeholder Text")) { entry in
WidgetView(entry: entry)
}
}
}
[/code]

Finalmente siamo pronti per mostrare il nostro Widget al mondo!

Preview

In SwiftUI puoi facilmente vedere l’anteprima del widget usando WidgetPreviewContext

Nel codice seguente presenteremo 3 viste di diverse dimensioni sul canvas.

[code lang=”swift”]
struct MyWidget_Previews: PreviewProvider {
static var previews: some View {
Group {
WidgetView(entry: WidgetEntry(date: Date(), value: 75))
.previewContext(WidgetPreviewContext(family: .systemSmall))
WidgetView(entry: WidgetEntry(date: Date(), value: 75))
.previewContext(WidgetPreviewContext(family: .systemMedium))
WidgetView(entry: WidgetEntry(date: Date(), value: 75))
.previewContext(WidgetPreviewContext(family: .systemLarge))
}
}
}
[/code]

Abbiamo fatto quindi una panoramica sui Widget statici di iOS14. Tra pochi giorni arriverà anche il progetto di esempio da scaricare (la prima beta di Mac OS Big Sur ha ancora qualche problema)

Ora tocca a te!

Menziona sui social iProg, e condividi i tuoi widgets!