Lernziel
Nach dieser Lektion kannst du eigene Bilder einbinden und richtig skalieren, SF Symbols gezielt einsetzen und gestalten, mit Systemfarben und eigenen Farben aus dem Asset-Katalog arbeiten und sicherstellen, dass alles auch im Dark Mode gut aussieht.
Das Problem: Bilder, die nicht passen
Ein Bild in eine App einzubauen, klingt einfach. Bis das Foto riesig über den Bildschirm hinausragt, verzerrt ist oder im Dark Mode ein grelles weißes Rechteck auf schwarzem Hintergrund erscheint.
In dieser Lektion lernst du drei Werkzeuge kennen: eigene Bilder, SF Symbols und Farben, und wie du sie so einsetzt, dass sie auf jedem iPhone und in jedem Modus gut aussehen.
Eigene Bilder
Ins Projekt holen
- Öffne im Navigator den Asset-Katalog
Assets. - Zieh eine Bilddatei (PNG, JPEG oder HEIC) aus dem Finder in die linke Spalte des Katalogs.
- Gib dem Bild einen Namen ohne Leerzeichen, zum Beispiel
mountain.
Dann zeigst du es so an:
Image("mountain")Erwartetes Ergebnis
Das Bild erscheint, aber vermutlich viel zu groß. Es wird in seiner Originalgröße angezeigt und ragt über den Bildschirm hinaus.
Größe anpassen
Ein Bild ist standardmäßig so groß wie seine Datei. Damit es sich anpassen kann, braucht es zuerst .resizable():
Image("mountain")
.resizable()
.scaledToFit()
.frame(height: 200).resizable(): Das Bild darf seine Größe ändern. Ohne diesen Modifier wirken Größenangaben nicht..scaledToFit(): Es wird so skaliert, dass es komplett sichtbar ist, ohne Verzerrung. Eventuell bleibt Platz frei..frame(height: 200): Der verfügbare Platz ist 200 Punkte hoch.
Die Alternative zu .scaledToFit() ist .scaledToFill(): Das Bild füllt den Platz vollständig aus, ohne Verzerrung, und ragt dafür über die Ränder hinaus. Mit .clipped() oder .clipShape(...) schneidest du den Überstand ab:
Image("mountain")
.resizable()
.scaledToFill()
.frame(width: 300, height: 200)
.clipShape(.rect(cornerRadius: 16))Fit oder Fill?
- Fit: Das ganze Bild ist wichtig, Ränder dürfen frei bleiben. Typisch für Produktfotos, Grafiken, Logos.
- Fill: Die Fläche soll komplett gefüllt sein, Ränder dürfen abgeschnitten werden. Typisch für Hintergründe, Profilbilder, Kacheln.
Runde Profilbilder
Ein Klassiker:
Image("portrait")
.resizable()
.scaledToFill()
.frame(width: 120, height: 120)
.clipShape(.circle)
.overlay {
Circle().stroke(.white, lineWidth: 4)
}
.shadow(radius: 6).overlay legt etwas vor die View (Lektion 2.4), hier einen weißen Kreisrand.
Bilder für Barrierefreiheit
Menschen, die nicht sehen können, nutzen VoiceOver: Das iPhone liest vor, was auf dem Bildschirm ist. Bei Bildern weiß es aber nicht, was darauf zu sehen ist. Hilf ihm:
Image("mountain", label: Text("Berggipfel im Morgenlicht"))
Image("decoration")
.accessibilityHidden(true) // rein dekorativ, wird übersprungenMehr dazu in Lektion 4.16. Mach es dir aber von Anfang an zur Gewohnheit.
SF Symbols
SF Symbols ist Apples Bibliothek mit Tausenden Symbolen. Du kennst sie seit Lektion 0.3: Image(systemName: "globe").
Die SF Symbols App
Lade dir die kostenlose App SF Symbols von Apples Entwicklerseite. Dort kannst du alle Symbole durchsuchen, ihre Namen kopieren und sehen, ab welcher iOS-Version es sie gibt. Ohne diese App ist es mühsam, den richtigen Namen zu finden.
Symbole verhalten sich wie Schrift
Das Besondere an SF Symbols: Sie verhalten sich wie Text. Sie haben keine feste Bildgröße, sondern passen sich der Schrift an:
Image(systemName: "heart.fill")
.font(.largeTitle)
.foregroundStyle(.red)
Label("Favoriten", systemImage: "heart.fill")
.font(.headline)- Größe über
.font(...), und damit wachsen sie mit Dynamic Type mit. - Farbe über
.foregroundStyle(...). .imageScale(.large)macht sie relativ zum umgebenden Text größer oder kleiner.
Label kombiniert ein Symbol mit einem Text und richtet beide perfekt aus. Du wirst es in Listen, Buttons und Menüs ständig verwenden.
Varianten und Darstellung
Viele Symbole gibt es in mehreren Varianten. Statt den Namen zu ändern, kannst du sie per Modifier wählen:
Image(systemName: "heart")
.symbolVariant(.fill) // wie "heart.fill"
Image(systemName: "bell")
.symbolVariant(.slash) // durchgestrichenUnd für mehrfarbige Symbole gibt es Rendering-Modi:
Image(systemName: "cloud.sun.rain.fill")
.symbolRenderingMode(.multicolor)
Image(systemName: "wifi")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.blue)| Modus | Wirkung |
|---|---|
.monochrome | eine Farbe (Standard) |
.hierarchical | eine Farbe in mehreren Abstufungen |
.palette | mehrere selbst gewählte Farben: .foregroundStyle(.blue, .yellow) |
.multicolor | Apples eingebaute Originalfarben |
Symbole animieren
Symbole können sich auch bewegen:
Image(systemName: "bell.fill")
.symbolEffect(.bounce, value: notificationCount)Jedes Mal, wenn sich notificationCount ändert, hüpft die Glocke. Es gibt viele weitere Effekte wie .pulse, .wiggle oder .rotate. Mehr zu Animationen in Lektion 3.23.
Farben
Systemfarben
SwiftUI bringt eine Palette vordefinierter Farben mit:
Color.red Color.orange Color.yellow Color.green
Color.mint Color.teal Color.cyan Color.blue
Color.indigo Color.purple Color.pink Color.brown
Color.gray Color.black Color.whiteWichtig: Diese Farben sind nicht fest. Apple stimmt sie für hellen und dunklen Modus leicht unterschiedlich ab, damit sie überall gut lesbar sind.
Semantische Farben
Noch besser sind Farben, die eine Bedeutung haben statt eines festen Farbtons:
Text("Haupttext").foregroundStyle(.primary)
Text("Nebentext").foregroundStyle(.secondary)
Button("Aktion") { }.tint(.accentColor)| Farbe | Bedeutung |
|---|---|
.primary | Haupttext: im hellen Modus fast schwarz, im dunklen fast weiß |
.secondary | gedämpfter Text |
.accentColor | die Akzentfarbe deiner App, z. B. für Buttons |
Color(.systemBackground) | Hintergrund: weiß bzw. schwarz |
Color(.secondarySystemBackground) | leicht abgesetzter Hintergrund für Karten |
Die Dark-Mode-Falle
.foregroundStyle(.black) sieht im hellen Modus gut aus und ist im dunklen Modus unsichtbar: schwarzer Text auf schwarzem Grund. Verwende für Texte und Hintergründe deshalb semantische Farben statt .black und .white.
Eigene Farben im Asset-Katalog
Für deine Markenfarben legst du eigene Farben an:
- Öffne
Assets. - Rechtsklick in die linke Spalte → New Color Set.
- Gib der Farbe einen Namen, z. B.
Brand. - Rechts im Attributes Inspector stellst du unter Appearances „Any, Dark“ ein. Dann kannst du je eine Variante für hellen und dunklen Modus festlegen.
Verwenden kannst du die Farbe dann so:
Text("Meine Marke")
.foregroundStyle(Color("Brand"))Neuere Xcode-Versionen erzeugen für jede Farbe im Katalog außerdem automatisch einen Namen, den du ohne Anführungszeichen nutzen kannst: Color(.brand) oder kurz .brand. Das hat einen großen Vorteil: Vertippst du dich, meldet Xcode sofort einen Fehler, statt die Farbe einfach nicht anzuzeigen.
Die Akzentfarbe der App
Im Asset-Katalog gibt es bereits eine Farbe namens AccentColor. Sie bestimmt die Grundfarbe deiner App: Buttons, Schalter, Links und markierte Elemente. Änderst du sie dort, ändert sich die ganze App auf einen Schlag.
Farbverläufe und Transparenz
Rectangle()
.fill(.blue.gradient)
.frame(height: 100)
Text("Halbtransparent")
.padding()
.background(.orange.opacity(0.3)).gradienterzeugt aus jeder Farbe einen dezenten, eleganten Verlauf..opacity(0.3)macht eine Farbe zu 30 % sichtbar.
Für Hintergründe, die den Inhalt dahinter durchscheinen lassen, gibt es Materialien: .background(.ultraThinMaterial). Diese milchglasartigen Flächen prägen das moderne iOS-Design. Mehr dazu in Lektion 3.30.
Typische Fehler
Größenänderung ohne Wirkung
Image("mountain")
.frame(width: 100, height: 100)Das Bild bleibt in Originalgröße. .resizable() fehlt und muss vor .frame stehen.
Verzerrtes Bild
Image("portrait")
.resizable()
.frame(width: 200, height: 100)Ohne .scaledToFit() oder .scaledToFill() wird das Bild auf genau diese Größe gestreckt. Ergänze einen der beiden.
Bild wird nicht angezeigt
Der Name stimmt nicht mit dem Namen im Asset-Katalog überein. Groß- und Kleinschreibung zählt. In der Konsole steht dann eine Meldung wie No image named 'Mountain' found in asset catalog.
Symbol-Name falsch
Image(systemName: "hearts") zeigt einfach nichts an, ohne Fehlermeldung beim Bauen. Prüf den Namen in der SF Symbols App.
.resizable() an der falschen Stelle
Image("mountain")
.scaledToFit()
.resizable()Fehlermeldung
Value of type 'some View' has no member 'resizable'
.resizable() gibt es nur direkt auf Image. Nach einem anderen Modifier ist es keine Image mehr, sondern eine eingewickelte View (Lektion 2.4). Schreib .resizable() immer als ersten Modifier.
FAQ
Anfänger
Was bedeutet das überhaupt?Welche Bildgröße sollte meine Datei haben? Für Fotos reicht meist eine Breite von etwa 1.000 bis 2.000 Pixeln. Größere Dateien machen die App unnötig groß. Für Grafiken wie Logos eignen sich Vektorformate wie PDF oder SVG, die in jeder Größe scharf bleiben.
Darf ich SF Symbols frei verwenden? In Apps für Apple-Plattformen ja. Es gibt aber Regeln, etwa dass manche Symbole nur für bestimmte Zwecke gedacht sind. Die SF Symbols App zeigt das an.
Wie finde ich heraus, wie meine App im Dark Mode aussieht?
In der Preview mit .preferredColorScheme(.dark) (Lektion 2.3) oder im Simulator unter Settings → Developer → Dark Appearance. Noch schneller: ⇧ ⌘ A im Simulator schaltet um.
Fortgeschritten
Warum verhält es sich so?Wie lade ich Bilder aus dem Internet?
Mit AsyncImage(url: ...). Es lädt das Bild selbst und zeigt währenddessen einen Platzhalter. Das lernst du in Projekt D (Rezept-App).
Was ist der Unterschied zwischen Color und foregroundStyle?
Color ist eine View und ein Farbwert. foregroundStyle akzeptiert jeden ShapeStyle: Farben, aber auch Verläufe, Materialien und semantische Stile wie .secondary. Deshalb ist .foregroundStyle flexibler als das ältere .foregroundColor.
Kann ich Farben im Code definieren, die sich an Dark Mode anpassen? Ja, aber das ist umständlicher als im Asset-Katalog. Für eine handvoll Markenfarben ist der Katalog der übliche Weg.
Profi
Was passiert unter der Haube?Wie geht SwiftUI mit Bildern für verschiedene Bildschirmauflösungen um?
iPhones haben Bildschirme mit zwei- oder dreifacher Pixeldichte. Im Asset-Katalog kannst du deshalb Varianten in @1x, @2x und @3x hinterlegen, und das System lädt automatisch die passende. Mit einem einzelnen Vektorbild oder „Single Scale“ übernimmt Xcode das für dich.
Was sind Template-Bilder?
Ein Bild im Modus Template (einstellbar im Attributes Inspector oder mit .renderingMode(.template)) wird wie ein SF Symbol behandelt: Nur seine Form zählt, die Farbe kommt aus .foregroundStyle. So passen sich eigene Icons an Akzentfarbe und Dark Mode an.
Übungen
Übung 1: Wetter-Symbole
Zeig nebeneinander drei Wetter-Symbole (sun.max.fill, cloud.rain.fill, cloud.bolt.fill) in der Größe .largeTitle und im Modus .multicolor.
Lösung Übung 1Erst selbst probieren!
HStack(spacing: 20) {
Image(systemName: "sun.max.fill")
Image(systemName: "cloud.rain.fill")
Image(systemName: "cloud.bolt.fill")
}
.font(.largeTitle)
.symbolRenderingMode(.multicolor)Weil .font und .symbolRenderingMode weitergegeben werden, reicht es, sie einmal am Stack anzugeben (Lektion 2.4).
Übung 2: Bildkachel
Zieh ein Foto in den Asset-Katalog und gestalte daraus eine Kachel: 300 × 200 Punkte, Bild füllt die Fläche, abgerundete Ecken mit Radius 20, darunter ein Titel. Prüf, wie es mit einem Hoch- und einem Querformat-Foto aussieht.
Übung 3: Eigene Farbe für hell und dunkel
Leg im Asset-Katalog eine Farbe CardBackground an: im hellen Modus ein sehr helles Grau, im dunklen ein dunkles Grau. Baue eine Karte mit Titel und Text auf diesem Hintergrund und prüf sie in beiden Modi in der Preview.
Zusammenfassung
- Eigene Bilder kommen in den Asset-Katalog und werden mit
Image("name")angezeigt. .resizable()muss zuerst stehen. Dann.scaledToFit()(alles sichtbar) oder.scaledToFill()(Fläche gefüllt).- SF Symbols verhalten sich wie Text: Größe über
.font, Farbe über.foregroundStyle. Labelkombiniert Symbol und Text.- Semantische Farben wie
.primaryundColor(.systemBackground)funktionieren im Dark Mode. - Eigene Farben legst du im Asset-Katalog mit Varianten für hell und dunkel an.
Spickzettel
Image("photo").resizable().scaledToFit().frame(height: 200)
Image("photo").resizable().scaledToFill().frame(width: 100, height: 100).clipShape(.circle)
Image(systemName: "heart.fill").font(.title).foregroundStyle(.red)
Label("Favoriten", systemImage: "star")
.symbolRenderingMode(.hierarchical)
.symbolEffect(.bounce, value: count)
.foregroundStyle(.secondary)
.background(Color(.secondarySystemBackground))
Color("Brand") .blue.gradient .orange.opacity(0.3)