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:
#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:
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.
Dark Mode und große Schrift
Für die häufigsten Varianten gibt es eingebaute Modifier:
#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.xSmallbis.accessibility5. Dieaccessibility-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:
#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:
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:
#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:
| Modus | Wofür |
|---|---|
| Live (Standard) | Die Preview ist interaktiv: Buttons, Schalter, Scrollen funktionieren |
| Selectable | Klick auf ein Element markiert die passende Codezeile, praktisch zum Zurechtfinden |
| Varianten | Zeigt Farbschema, Schriftgröße oder Ausrichtung in allen Varianten |
| Gerät | Wä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
#Preview {
BookRow()
}Fehlermeldung
Missing argument for parameter 'book' in call
Die View braucht Daten. Übergib zum Beispiel BookRow(book: .example).
@State ohne @Previewable
#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
Ü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!
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)
}Ü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?
Ü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!
#Preview {
@Previewable @State var count = 0
VStack(spacing: 20) {
Text("\(count)")
.font(.largeTitle)
Button("Plus eins") {
count += 1
}
}
}Zusammenfassung
#Previewzeigt 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
.landscapeLeftund.sizeThatFitsLayoutändern Ausrichtung und Rahmen. - Beispieldaten in einer Extension (
static let example) sind überall wiederverwendbar. @Previewable @Stateermöglicht interaktive Previews.- Previews ersetzen nicht den Test im Simulator.
Spickzettel
#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)
}