[SWIFT] Hinzufügen von Widgets für iOS 14-Anwendungen (reguläre Widgets, konfigurierbare Widgets mit Absichten)

** Dieser Artikel beschreibt Folgendes: ** ** **

  1. Fügen Sie einer vorhandenen Anwendung ein Widget hinzu
  2. ⭐️ Fügen Sie Widgets hinzu, mit denen Benutzer Inhalte konfigurieren können (z. B. Stadtauswahl).

ezgif-6-bf9e4b4783c9.gif

Den vollständigen Quellcode können Sie hier überprüfen.

Hinzufügen von Widgets zu vorhandenen Anwendungen

Erstellen eines Anwendungsziels

Das Hinzufügen von Widgets zu vorhandenen iOS-Anwendungen ist einfach. Fügen Sie die Ziel-Widget-Erweiterung hinzu.

image

Stellen Sie nun sicher, dass Sie das Kontrollkästchen "Konfigurationsabsicht einschließen" aktiviert haben. Das liegt daran, dass Sie diese Konfigurationsdatei in Teil 2 dieses Artikels benötigen.

image

Datenstruktur

Sie sollten jetzt einen neuen Ordner namens "WidgetExample-Widget" sehen. Klicken Sie hier, um die Datei "WidgetExample_Widget.swift" zu öffnen, den Inhalt dieser Datei zu löschen und dieser Anleitung zu folgen.

Sie können die Datenstruktur der Daten erstellen, die im Widget angezeigt werden sollen. In diesem Beispiel werden die Katzeninformationen angezeigt!

struct CatEntry: TimelineEntry {
    var date: Date
    
    var name: String
    var lastFed: Date
    var lastPlayedWith: Date
}

Erstellen einer IntentTimelineProvider-Struktur

Die IntentTimelineProvider-Struktur bietet drei Arten von Inhalten: 1> Platzhalter wird angezeigt, wenn das Widget geladen wird. 2> getSnapshot wird in der Widget-Galerie angezeigt. 3> getTimeline wird für die eigentliche Widget-Anzeige verwendet.

Erstellen Sie zunächst eine Programmstruktur, die nach dem Typ "IntentTimelineProvider" sucht, und definieren Sie dann den Typ für "Eintrag".

struct CatProviderStatic: TimelineProvider {
    typealias Entry = CatEntry

    func getSnapshot(in context: Context, completion: @escaping (CatEntry) -> Void) {
        //TODO
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) {
        //TODO
    }

    func placeholder(in context: Context) -> CatEntry {
        //TODO
    }

}

Für die Funktion "getSnapshot" können Sie einen Beispielwert in der Widget-Ansicht angeben, damit der Benutzer verstehen kann, welche Informationen Ihr Widget bereitstellt:

func getSnapshot(in context: Context, completion: @escaping (CatEntry) -> Void) {
    let entry = CatEntry(date: Date(), name: "Katzenname", lastFed: Date(), lastPlayedWith: Date())
    completion(entry)
}

In Platzhalteransichten können Sie leere Werte oder Beispielwerte wie folgt anzeigen:

func placeholder(in context: Context) -> CatEntry {
    return CatEntry(date: Date(), name: "Katzenname", lastFed: Date(), lastPlayedWith: Date())
}

Für die Timeline-Anzeige können Sie den tatsächlich anzuzeigenden Inhalt bereitstellen.

In diesem Beispiel werden nur statische Datenwerte angezeigt. In Ihrer Anwendung "Kerndaten" (Klicken Sie hier, um einen Artikel zum Teilen dieser Daten zu erhalten) oder online über "CloudKit" oder Sie können Inhalte aus "UserDefaults" abrufen.

func getTimeline(in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) {
    let entry = CatEntry(date: Date(), name: "Nekonohi", lastFed: Date(), lastPlayedWith: Date())
    let timeline = Timeline(entries: [entry], policy: .atEnd)
    completion(timeline)
}

Widget-Ansichtsdesign

Sie können jetzt die SwiftUI-Ansicht des Widgets entwerfen.

struct CatWidgetView: View {
    
    @Environment(\.widgetFamily) var family
    
    var entry: CatEntry
    
    var body: some View {
        
        VStack {
            
            if family == .systemMedium || family == .systemLarge {
                Image("kitty")
                    .resizable()
                    .frame(width: 50, height: 50)
                    .padding(.vertical, 5)
            }
            
            Text(entry.name)
                .font(.headline)
                .padding(1)
            
            Text("Letzte gespielte Zeit" + entry.lastPlayedWith.getString())
                .font(.caption)
                .padding(.horizontal)
            
            Text("Letzte Fütterungszeit" + entry.lastFed.getString())
                .font(.caption)
                .padding(.horizontal)
            
        }
        
    }
    
}

Sie können die Variable "@Environment (\ .widgetFamily) var family" verwenden, um die Größe des Widgets anzuzeigen.

Dieses Beispiel zeigt ein Bild einer Katze, wenn das Widget groß genug ist, um das Bild anzuzeigen.

if family == .systemMedium || family == .systemLarge {
    Image("kitty")
        .resizable()
        .frame(width: 50, height: 50)
        .padding(.vertical, 5)
}

Codieren einer Widget-Anwendung

Sie können jetzt Ihre Widget-Anwendung codieren.

@main
struct CatWidget: Widget {
    
    var body: some WidgetConfiguration {
        IntentConfiguration(kind: "CatWidget", intent: ConfigurationIntent.self, provider: CatProvider()) { entry in
            CatWidgetView(entry: entry)
        }.configurationDisplayName("Katze")
        .description("Sehen Sie, wann Sie mit Ihrer Katze gefüttert und gespielt haben.")
    }
    
}

Sie können die App jetzt im Simulator ausführen und das gerade erstellte Widget zu Ihrem Bildschirm hinzufügen.

image

Ermöglicht Benutzern das Konfigurieren von Widgets

Wenn Sie das Wetter-Widget verwendet haben, wissen Sie, dass Benutzer durch langes Drücken und Konfigurieren des Widgets auswählen können, welche Städte angezeigt werden sollen. Sie können diese Funktionalität mithilfe des Intents-Frameworks und des Ziels hinzufügen.

Absichten Programmziel hinzufügen

image

Sie benötigen zu diesem Zeitpunkt keine UI-Elemente, daher können Sie die Option "UI-Erweiterung einschließen" deaktivieren.

image

Suchen Sie auf der Zielseite für erstellte Absichten den Abschnitt "Unterstützte Absichten". Erstellen Sie ein neues Element mit dem Namen "ConfigurationIntent". Der Name ist "[Absichtsname] Absicht". Der Intent-Name wird in der Datei ".intentdefinition" auf der linken Seite angezeigt.

スクリーンショット 0002-10-09 15.16.55.png

スクリーンショット 0002-10-09 15.11.01.png

Struktur der ".intentdefinition"

Fügen Sie dann für die Datei "WidgetExample_Widget.intentdefinition" im zuvor erstellten Widget die neu erstellte Erweiterung "Intents" als Intent-Ziel hinzu.

<img width="300 alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/a9450674-1f3b-9d1d-f8c0-69221b74e7c2.png ">

Klicken Sie auf der linken Seite des Bildschirms auf "Konfiguration".

image

Stellen Sie auf der rechten Seite sicher, dass es dieselbe Konfiguration wie im Bild unten hat.

image

Fügen Sie dann einen neuen Parameter mit dem Namen "cat" hinzu.

image

Wählen Sie im neu erstellten Einstellungsbildschirm "cat" die Option "String" für den Typ "Type" aus, um die cat-ID als Eingabe zu verwenden.

image

Konfiguration von IntentHandler

Öffnen Sie dann die Datei "IntentHandler.swift". Diese Datei gibt dem Benutzer die Möglichkeit, das Widget zu konfigurieren. In diesem Beispiel ist die Option die Kennung der Katze.

Wenn Sie das Schlüsselwort "ConfigurationIntentHandling" neben dem Typ "INExtension" der Klasse hinzufügen, zeigt die Xcode-Software automatisch den Namen der nächsten hinzuzufügenden Funktion an.

class IntentHandler: INExtension, ConfigurationIntentHandling {
    ...
}

In diesem Beispiel sieht die fertige Datei "IntentHandler.swift" folgendermaßen aus:

class IntentHandler: INExtension, ConfigurationIntentHandling {
    
    
    func provideCatOptionsCollection(for intent: ConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) {
        let catIdentifiers: [NSString] = [
            "Nekonohi",
            "Weizen",
            "Azuki"
        ]
        let allCatIdentifiers = INObjectCollection(items: catIdentifiers)
        completion(allCatIdentifiers, nil)
    }
    
    override func handler(for intent: INIntent) -> Any {
        // This is the default implementation.  If you want different objects to handle different intents,
        // you can override this and return the handler you want for that particular intent.
        
        return self
    }
    
}

Für die Funktion "requireCatOptionsCollection" müssen Sie eine Werteliste eingeben. Diese Werte können tatsächlich entweder aus "User Defaults", "Core Data" oder online abgerufen werden. Die Werte sind in diesem Beispiel fest codiert.

Verwenden Sie "Core Data" mit "App Extensions"

Erstellen Sie "IntentTimelineProvider"

In Teil 1 dieses Artikels haben wir "TimelineProvider" verwendet. Dieses Mal werden wir "IntentTimelineProvider" verwenden.

Die Datenstruktur zwischen "IntentTimelineProvider" und "TimelineProvider" ist ungefähr gleich. Der Unterschied besteht darin, dass Sie zusätzliche Typealien deklarieren müssen.

typealias Intent = ConfigurationIntent

Ein weiterer Unterschied ist: Jede Funktion erhält einen zusätzlichen Parameter "ConfigurationIntent", der die Auswahl der Absichten darstellt.

struct CatProvider: IntentTimelineProvider {
    
    typealias Intent = ConfigurationIntent
    typealias Entry = CatEntry
    
    func placeholder(in context: Context) -> CatEntry {
        let entry = CatEntry(date: Date(), name: "", lastFed: Date(), lastPlayedWith: Date())
        return entry
    }
    
    func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (CatEntry) -> Void) {
        let entry = CatEntry(date: Date(), name: "Katzenname", lastFed: Date(), lastPlayedWith: Date())
        completion(entry)
    }
    
    func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<CatEntry>) -> Void) {
        let entry = CatEntry(date: Date(), name: configuration.cat ?? "", lastFed: Date(), lastPlayedWith: Date())
        let timeline = Timeline(entries: [entry], policy: .atEnd)
        completion(timeline)
    }
    
}

Mit der Eigenschaft configuration.cat können Sie den Wert der vom Benutzer ausgewählten Option lesen.

let entry = CatEntry(date: Date(), name: configuration.cat ?? "", lastFed: Date(), lastPlayedWith: Date())

Aktualisieren Sie den Code für "CatWidget".

Wir haben in Teil 1 "StaticConfiguration" verwendet, aber dieser Teil verwendet "IntentConfiguration" (den Namen, den Sie in "Supported Intents" festgelegt haben).

@main
struct CatWidget: Widget {
    
    var body: some WidgetConfiguration {
        IntentConfiguration(kind: "CatWidget", intent: ConfigurationIntent.self, provider: CatProvider()) { entry in
            CatWidgetView(entry: entry)
        }.configurationDisplayName("Katze")
        .description("Sehen Sie, wann Sie mit Ihrer Katze gefüttert und gespielt haben.")
    }
    
}

Sie können das Programm jetzt im Simulator ausführen. Halten Sie das Widget gedrückt, um die Option "Kanten-Widget" anzuzeigen, mit der Sie die Katze umbenennen können.

ezgif-6-bf9e4b4783c9.gif

⭐️

Verwenden Sie "Core Data" mit "App Extensions"

Auf dieser Webseite finden Sie eine Liste meiner veröffentlichten Qiita-Artikel nach Kategorien.

Recommended Posts

Hinzufügen von Widgets für iOS 14-Anwendungen (reguläre Widgets, konfigurierbare Widgets mit Absichten)
Hinweise zur Verwendung von BLE in iOS-Apps
Trackpad-Unterstützung (UIPointerInteraction) für iPad iOS-Anwendungen hinzugefügt