Lektion 2.3 · Stufe 2 – SwiftUI-Einstieg

Previews als Werkzeug

ca. 15 Minuten Lesezeit

Lernziel

Nach dieser Lektion nutzt du Previews als echtes Werkzeug: mehrere benannte Previews, Dark Mode, große Schrift, verschiedene Geräte und Querformat, Previews mit Beispieldaten und mit eigenem Zustand dank @Previewable. Außerdem kennst du die wichtigsten Modi des Canvas.

Das Problem: Eine View, viele Situationen

Eine View sieht nicht immer gleich aus. Dieselbe Profilkarte muss funktionieren:

  • im hellen und im dunklen Modus,
  • mit normaler und mit sehr großer Schrift, denn viele Menschen stellen auf ihrem iPhone größere Schrift ein,
  • auf einem kleinen und einem großen iPhone,
  • mit einem kurzen Namen wie „Li“ und einem langen wie „Maximiliane Hohenzollern-Sigmaringen“.

Alle diese Fälle jedes Mal im Simulator durchzuspielen, dauert ewig. Und deshalb wird es meist nicht gemacht, bis ein Nutzer sich beschwert.

Mit Previews siehst du alle Varianten gleichzeitig, live, während du tippst.

Die einfachste Preview

Aus Lektion 0.3 kennst du schon:

Swift
#Preview {
    ContentView()
}

#Preview ist ein Makro. Das erkennst du am #. Ein Makro ist Code, der beim Übersetzen weiteren Code erzeugt. Du musst nicht wissen, was es genau erzeugt. Wichtig ist: Alles in den geschweiften Klammern wird im Canvas angezeigt.

Previews werden nur in Xcode verwendet. In der fertigen App auf dem iPhone spielen sie keine Rolle.

Mehrere Previews

Du darfst so viele #Preview-Blöcke schreiben, wie du willst. Gib ihnen Namen, damit du sie im Canvas unterscheiden kannst:

Swift
struct GreetingView: View {
    let name: String

    var body: some View {
        Text("Hallo, \(name)!")
            .font(.largeTitle)
            .padding()
            .background(.yellow.opacity(0.3))
    }
}

#Preview("Kurzer Name") {
    GreetingView(name: "Li")
}

#Preview("Langer Name") {
    GreetingView(name: "Maximiliane Hohenzollern-Sigmaringen")
}

Im Canvas erscheinen oben Reiter für jede Preview. Ein Klick wechselt zwischen ihnen.

Erwartetes Ergebnis

Zwei Reiter „Kurzer Name“ und „Langer Name“. Beim langen Namen siehst du sofort, ob der Text sauber umbricht.

Screenshot folgt: Canvas mit zwei Preview-Reitern

Dark Mode und große Schrift

Für die häufigsten Varianten gibt es eingebaute Modifier:

Swift
#Preview("Dunkel") {
    GreetingView(name: "Anna")
        .preferredColorScheme(.dark)
}

#Preview("Große Schrift") {
    GreetingView(name: "Anna")
        .dynamicTypeSize(.accessibility3)
}
  • .preferredColorScheme(.dark) zeigt die View im dunklen Modus.
  • .dynamicTypeSize(...) simuliert eine andere Schriftgröße. Die Werte reichen von .xSmall bis .accessibility5. Die accessibility-Stufen sind sehr groß und werden von Menschen mit eingeschränkter Sehkraft genutzt.

Varianten auf Knopfdruck

Unten im Canvas gibt es eine Schaltfläche für Varianten (Symbol mit mehreren Rechtecken). Damit zeigt Xcode deine Preview automatisch in allen Farbschemata, allen Schriftgrößen oder beiden Ausrichtungen nebeneinander, ganz ohne zusätzlichen Code. Ideal für einen schnellen Rundumblick.

Geräte und Ausrichtung

Welches Gerät der Canvas zeigt, wählst du unten im Canvas über die Geräteauswahl. Für Querformat oder ein kompaktes Layout gibt es Traits:

Swift
#Preview("Querformat", traits: .landscapeLeft) {
    GreetingView(name: "Anna")
}

#Preview("Nur die View", traits: .sizeThatFitsLayout) {
    GreetingView(name: "Anna")
}

.sizeThatFitsLayout zeigt nur die View selbst, ohne iPhone-Rahmen drumherum. Das ist praktisch für kleine Bausteine wie Buttons oder Zeilen.

Previews mit Beispieldaten

Sobald Views eigene Daten bekommen, brauchst du in der Preview passende Beispiele. Ein bewährtes Muster kennst du aus Lektion 1.16:

Swift
struct Book {
    let title: String
    let author: String
    let pages: Int
}

extension Book {
    static let example = Book(title: "Momo", author: "Michael Ende", pages: 304)
    static let longTitle = Book(
        title: "Die unendliche Geschichte von Bastian Balthasar Bux",
        author: "Michael Ende",
        pages: 480
    )
}

struct BookRow: View {
    let book: Book

    var body: some View {
        VStack(alignment: .leading) {
            Text(book.title)
                .font(.headline)
            Text("\(book.author) · \(book.pages) Seiten")
                .foregroundStyle(.secondary)
        }
    }
}

#Preview("Normal") {
    BookRow(book: .example)
}

#Preview("Langer Titel") {
    BookRow(book: .longTitle)
}

Die Beispieldaten stehen an einer Stelle und sind überall wiederverwendbar. In Projekt C und allen weiteren Projekten arbeiten wir genau so.

Tipp

Mach es dir zur Gewohnheit, Grenzfälle als eigene Preview anzulegen: leerer Text, sehr langer Text, Zahl 0, eine sehr große Zahl, kein Bild. Die meisten Darstellungsfehler verstecken sich genau dort.

Previews mit Zustand: @Previewable

Manche Views brauchen nicht nur Daten, sondern einen veränderbaren Wert, mit dem man in der Preview interagieren kann. Das betrifft vor allem Views mit @Binding (Lektion 2.10). Dafür gibt es @Previewable:

Swift
#Preview {
    @Previewable @State var isOn = true
    Toggle("WLAN", isOn: $isOn)
        .padding()
}

Im interaktiven Canvas kannst du den Schalter dann wirklich umlegen. Was @State und $ bedeuten, lernst du in den Lektionen 2.9 und 2.10. Merk dir das Muster für später.

Die Modi des Canvas

Unten im Canvas findest du einige Schaltflächen. Die wichtigsten:

ModusWofür
Live (Standard)Die Preview ist interaktiv: Buttons, Schalter, Scrollen funktionieren
SelectableKlick auf ein Element markiert die passende Codezeile, praktisch zum Zurechtfinden
VariantenZeigt Farbschema, Schriftgröße oder Ausrichtung in allen Varianten
GerätWählt das iPhone-Modell für die Preview

Außerdem kannst du mit dem Pin-Symbol eine Preview anheften. Dann bleibt sie sichtbar, auch wenn du im Editor zu einer anderen Datei wechselst. Sehr praktisch, wenn du eine kleine Komponente bearbeitest und gleichzeitig sehen willst, wie sie im großen Bildschirm wirkt.

Wenn die Preview streikt

Previews sind großartig, aber manchmal empfindlich. Die häufigsten Probleme:

  • „Preview paused“: Xcode wartet. Klick auf den Aktualisieren-Pfeil oder drück ⌥ ⌘ P.
  • Fehlermeldung im Canvas: Meist gibt es einen Fehler im Code. Behebe zuerst alle roten Fehler im Editor.
  • „Cannot preview in this file“: Oft hilft Editor → Canvas zweimal (aus und an) oder ein Neustart von Xcode.
  • Absturz in der Preview: Klick auf Diagnostics. Dort steht, welche Zeile abgestürzt ist, oft ein ! oder ein Index außerhalb eines Arrays.

Achtung

Previews sind kein Ersatz für den Simulator oder ein echtes Gerät. Navigation über mehrere Bildschirme, Tastatur, Benachrichtigungen und das Verhalten beim Starten testest du immer auch „richtig“ mit ⌘ R.

Typische Fehler

Preview zeigt eine leere Fläche

Die View hat keine Größe, etwa ein leeres VStack oder ein Text mit leerem String. Füg Beispieldaten hinzu oder prüf, ob deine Bedingungen vielleicht alles ausblenden.

Argument fehlt

Swift
#Preview {
    BookRow()
}

Fehlermeldung

Missing argument for parameter 'book' in call

Die View braucht Daten. Übergib zum Beispiel BookRow(book: .example).

@State ohne @Previewable

Swift
#Preview {
    @State var isOn = true
    Toggle("WLAN", isOn: $isOn)
}

Fehlermeldung

Je nach Xcode-Version eine Fehlermeldung, die auf @Previewable hinweist.

Variablen mit Property Wrappern brauchen in Previews das Präfix @Previewable.

FAQ

Anfänger

Was bedeutet das überhaupt?

Kosten Previews Leistung in der fertigen App? Nein. Previews werden nur in Xcode ausgeführt und nicht in die App für den App Store eingebaut.

Warum ist meine Preview so langsam? Beim ersten Mal muss Xcode die App bauen. Danach geht es meist schnell. Werden Previews sehr träge, schließ nicht benötigte Programme. Bei großen Projekten lohnt es sich, Code in kleinere Pakete aufzuteilen (Lektion 4.14).

Wie viele Previews sollte eine Datei haben? So viele, wie sinnvolle Situationen existieren. Für eine einfache View reicht oft eine. Für eine wichtige, wiederverwendete Komponente sind drei bis fünf Varianten völlig normal.

Fortgeschritten

Warum verhält es sich so?

Kann ich eine View in einer Navigation oder Liste previewen? Ja, du kannst in den Preview-Block beliebigen SwiftUI-Code schreiben: #Preview { NavigationStack { DetailView(book: .example) } }. So siehst du eine Detailansicht gleich mit Navigationsleiste.

Wie gebe ich einer Preview Daten aus der Umgebung? Mit denselben Modifiern wie in der App, zum Beispiel .environment(...) oder .modelContainer(...). Für wiederkehrende Vorbereitung gibt es eigene Preview-Modifier, die man über traits anwenden kann. Das lernst du, sobald du SwiftData verwendest (Lektion 3.14).

Profi

Was passiert unter der Haube?

Wie schafft Xcode es, Änderungen so schnell anzuzeigen? Xcode baut die Datei in einem speziellen Modus und lädt geänderte Funktionen zur Laufzeit nach, ohne die ganze App neu zu bauen. Ändert sich aber die Struktur eines Typs, etwa eine neue gespeicherte Eigenschaft, ist ein kompletter Neubau nötig. Deshalb sind manche Änderungen sofort sichtbar und andere brauchen ein paar Sekunden.

Was macht @Previewable technisch? Es ist ein Makro, das deinen Preview-Inhalt in eine versteckte Hilfs-View einpackt und die markierten Variablen zu deren Eigenschaften macht. Nur so können Property Wrapper wie @State funktionieren, die eine View als „Besitzer“ brauchen.

Übungen

Anfänger

Übung 1: Drei Varianten

Baue eine kleine View PriceTag, die einen Preis als Text in einem gelben Kasten zeigt. Leg drei Previews an: normal, Dark Mode und größte Barrierefreiheitsschrift.

Lösung Übung 1Erst selbst probieren!
Swift
struct PriceTag: View {
    let price: String

    var body: some View {
        Text(price)
            .font(.title)
            .padding()
            .background(.yellow)
    }
}

#Preview("Normal") {
    PriceTag(price: "19,99 €")
}

#Preview("Dunkel") {
    PriceTag(price: "19,99 €")
        .preferredColorScheme(.dark)
}

#Preview("Riesig") {
    PriceTag(price: "19,99 €")
        .dynamicTypeSize(.accessibility5)
}
Fortgeschritten

Übung 2: Grenzfälle finden

Baue eine MessageRow mit Absender und Nachrichtentext. Leg Beispieldaten in einer Extension an und schreib Previews für: normale Nachricht, leere Nachricht, sehr lange Nachricht, sehr langer Absendername. Welche Darstellungsprobleme entdeckst du?

Profi

Übung 3: Interaktive Preview

Schreib eine Preview mit @Previewable @State var count = 0, die einen Text mit dem Wert und einen Button zeigt, der den Wert erhöht. Schalte den Canvas in den Live-Modus und probier es aus.

Lösung Übung 3Erst selbst probieren!
Swift
#Preview {
    @Previewable @State var count = 0

    VStack(spacing: 20) {
        Text("\(count)")
            .font(.largeTitle)
        Button("Plus eins") {
            count += 1
        }
    }
}

Zusammenfassung

  • #Preview zeigt Views live im Canvas, nur in Xcode.
  • Mehrere benannte Previews zeigen verschiedene Situationen.
  • .preferredColorScheme(.dark) und .dynamicTypeSize(...) prüfen Dark Mode und große Schrift.
  • Traits wie .landscapeLeft und .sizeThatFitsLayout ändern Ausrichtung und Rahmen.
  • Beispieldaten in einer Extension (static let example) sind überall wiederverwendbar.
  • @Previewable @State ermöglicht interaktive Previews.
  • Previews ersetzen nicht den Test im Simulator.

Spickzettel

Swift
#Preview("Name") { MyView() }
#Preview("Dunkel") { MyView().preferredColorScheme(.dark) }
#Preview("Groß") { MyView().dynamicTypeSize(.accessibility3) }
#Preview(traits: .landscapeLeft) { MyView() }
#Preview(traits: .sizeThatFitsLayout) { MyRow() }
#Preview {
    @Previewable @State var on = true
    Toggle("An", isOn: $on)
}

Lektion geschafft?

Markiere sie als erledigt, damit du deinen Fortschritt siehst.