SwiftUI in der Praxis – Teil 5

Alert mit Textfeld erstellen und anzeigen

Alerts in SwiftUI sind – zumindest bisher – enorm auf Einfachheit getrimmt. Bei ihrer Konfiguration ist es lediglich möglich, einen Titel, eine Beschreibung sowie maximal zwei Buttons zu setzen.

Sicher mag das für viele Einsatzszenarien ausreichend sein, weshalb ich die Einfachheit von Alerts in SwiftUI durchaus begrüße. Doch so ist es unmöglich, aufwendigere Alerts in SwiftUI umzusetzen. Im Falle einer iOS- bzw. iPadOS-App ist es daher in bestimmten Szenarien notwendig, auf eine UIAlertController-Instanz zurückzugreifen.

Ich selbst nutze beispielsweise sehr gerne Alerts, über die mittels Textfeld eine Information eingegeben werden soll. Alerts sind in meinen Augen perfekt, um schnell und unkompliziert neue Datensätze auf Basis eines einfachen Strings zu erzeugen. Mit einem UIAlertController lässt sich ein solcher Alert auch ohne Probleme umsetzen. In SwiftUI geht das hingegen gar nicht.

Da ich selbst schon des Öfteren einen Alert mit Textfeld auch in SwiftUI-Apps benötigt habe, möchte ich euch in diesem Artikel zeigen, wie ihr aus einer SwiftUI-View heraus eine UIAlertController-Instanz erzeugt und einblendet. Hierbei möchte ich vorab betonen, dass das gezeigte Vorgehen sehr simpel gehalten ist und – gerade im Falle von iPadOS und dem Einsatz mehrerer Fenster für eine App – durchaus noch Optimierungspotential besitzt.

UIAlertController konfigurieren

Als Basis dient zunächst einmal der nachfolgende Code. Er zeigt eine SwiftUI-View namens ShowAlertButton, die einen Alert mit Textfeld auf Basis der UIAlertController-Klasse anzeigen soll. Entsprechend besteht der Body der View schlicht aus einem Button, der den Text „Show alert with text field“ anzeigt und bei Betätigung eine Methode namens presentTextFieldAlertController() aufruft (zu deren Implementierung kommen wir gleich).

Der Alert-Controller, der angezeigt werden soll, wird über eine private Property namens textFieldAlertController erzeugt. Die größte Besonderheit dieses Alert-Controllers besteht in dem Textfeld, das reine SwiftUI-Alerts in dieser Form nicht nutzen können. Daneben besitzt der Alert-Controller zwei Buttons. Einer soll die Aktion abbrechen, der andere ein Item auf Basis des angegebenen Titels erzeugen. Da die Model-Haltung in diesem Artikel keine Rolle spielt, spare ich mir konkrete Speichermechanismen und Model-Strukturen an dieser Stelle aus. Es geht lediglich darum, den Zugriff auf den Alert-Controller zu demonstrieren.

struct ShowAlertButton: View {
    private var textFieldAlertController: UIAlertController {
        let textFieldAlertController = UIAlertController(title: NSLocalizedString("Add new item", comment: "Add new item"), message: nil, preferredStyle: .alert)
        textFieldAlertController.addTextField { (textField) in
            textField.autocapitalizationType = .sentences
        }
        let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel"), style: .cancel, handler: nil)
        let saveAction = UIAlertAction(title: NSLocalizedString("Save", comment: "Save"), style: .default) { (alertAction) in
            let itemTextField = textFieldAlertController.textFields![0]
            let item = groupTextField.text
            // Save item ...
            }
        }
        textFieldAlertController.addAction(cancelAction)
        textFieldAlertController.addAction(saveAction)
        return textFieldAlertController
    }
    
    var body: some View {
        Button(action: {
            self.presentTextFieldAlertController()
        }) {
            Text("Show alert with text field")
        }
    }
    
    private func presentTextFieldAlertController() {
        // TODO: Implement ...
    }
}

Einblenden des Alert-Controllers

Kommen wir nun zum spannenden Teil, der Implementierung der presentTextFieldAlertController()-Methode. Normalerweise nutzen wir in SwiftUI einen Status, um das Ein- und Ausblenden neuer Views zu steuern. Da wir in diesem Fall aber direkt mit einem UIViewController arbeiten, nutzen wir auch die entsprechenden Mechanismen des UIKit-Frameworks, um unseren Alert-Controller einzublenden.

Dazu greifen wir über das UIApplication-Singleton auf die verfügbaren Windows unserer App zu und wählen – der Einfachheit halber – an dieser Stelle schlicht das erste aus (für reine iOS-Anwendungen ist das auch vollkommen in Ordnung). Über dieses Window greifen wir dann auf den zugehörigen Root-View-Controller zu und nutzen den, um mittels Aufruf der present(_:animated:)-Methode unseren Alert-Controller einzublenden.

Spannend hieran ist, dass wir es – obwohl wir uns in SwiftUI-Views bewegen – in der Basis noch immer mit View-Controllern zu tun haben und auf diese auch zugreifen können.

In diesem Kontext prüfen wir innerhalb der presentTextFieldAlertController()-Methode ergänzend, ob der ausgelesene Root-View-Controller einen Presented-View-Controller besitzt. Das ist beispielsweise dann der Fall, wenn wir in SwiftUI ein Sheet modal einblenden und die Methode daraus heraus aufrufen. Ist das der Fall, funktioniert das Einblenden unseres Alert-Controllers über den Root-View-Controller nicht. Stattdessen müssen wir dann zwingend über den Presented-View-Controller gehen.

private func presentTextFieldAlertController() {
    if let rootViewController = UIApplication.shared.windows[0].rootViewController {
        if let presentedViewController = rootViewController.presentedViewController {
            presentedViewController.present(textFieldAlertController, animated: true)
        } else {
            rootViewController.present(textFieldAlertController, animated: true)
        }
    }
}

Fazit

Beim Zusammenspiel zwischen dem Dreiergespann AppKit/UIKit/WatchKit und SwiftUI hat Apple bereits sehr gute Arbeit geleistet. Eine Mischung der genannten Technologien ist ohne großen Aufwand möglich und die Ergebnisse enorm gelungen. Wie wir gesehen haben, ist so auch der Einsatz eines UIAlertController unter SwiftUI kein wirkliches Problem. Das stimmt milde, solange die Alert-Structure aus SwiftUI selbst lediglich die Umsetzung sehr simpler Alerts ermöglicht.

Euer Thomas

Bisherige Artikel in dieser Serie


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert