Entwickler
Zeilenhöhe in SwiftUI: der lineHeight-Modifier aus iOS 26 erklärt
Zeilenhöhe in SwiftUI ab iOS 26: Presets von .lineHeight, multiple(factor:), exakte Werte und Leading, der Vergleich mit lineSpacing, auf iPhone und iPhone Duo.
Von der AppleDuo-RedaktionVeröffentlicht 6 Min. Lesezeit
Auf dieser Seite
- Wie setze ich die Zeilenhöhe in SwiftUI?
- Was bedeuten .tight, .normal und .loose?
- Wie verhält sich .multiple(factor:) zu CSS line-height?
- Warum sitzt ein einzeiliges Label mit lineHeight zu hoch?
- Was ist der Unterschied zwischen lineHeight, lineSpacing und leading?
- Wie lasse ich Zahlen mit contentTransition(.numericText()) rollen?
- Ist die Zeilenhöhe auf dem iPhone Duo wichtiger?
- Das Wichtigste in Kürze
Designer liefern Vorgaben wie „17 pt, Zeilenhöhe 1,5“, und lange gab es in SwiftUI keinen direkten Weg, das auszudrücken. Man näherte sich mit .lineSpacing an, das Punkte zwischen Zeilen einfügt, oder mit .leading einer Schrift, das drei feine Stufen bietet. iOS 26 behebt das mit einem echten Modifier für die Zeilenhöhe in SwiftUI.
Dieser Leitfaden behandelt den Modifier lineHeight(_:), jeden Wert, den er akzeptiert, den Vergleich mit den älteren APIs und das eine Verhalten, das viele überrascht: wohin der zusätzliche Platz geht. Er basiert auf Apples Dokumentation, dem Artikel von Natalia Panferova auf Nil Coalescing und Beiträgen des iOS-Entwicklers @sarunw. Der Modifier ist neu in iOS 26.0, und Details können sich zwischen Releases ändern.
Wie setze ich die Zeilenhöhe in SwiftUI?
Wenden Sie .lineHeight(_:) auf einen Text an oder auf eine beliebige View darüber. Apple beschreibt ihn als Modifier für die Standard-Zeilenhöhe in der View-Hierarchie, er wirkt also wie .font über das Environment:
Text(article.body)
.font(.body)
.lineHeight(.loose)
Der Parameter ist ein optionales AttributedString.LineHeight, ein Foundation-Typ, den Apple als Abstand zwischen den Grundlinien zweier aufeinanderfolgender Zeilen definiert. Der Standard ist nil, und in diesem Fall wählt SwiftUI laut Apple automatisch eine passende Zeilenhöhe für jeden Kontext. Übergeben Sie nil, um einen Teilbaum wieder auf dieses automatische Verhalten zurückzusetzen.
Der Modifier und der passende Environment-Wert lineHeight sind ab iOS 26.0, iPadOS 26.0, macOS 26.0, Mac Catalyst 26.0, tvOS 26.0, visionOS 26.0 und watchOS 26.0 verfügbar. Es gibt kein Back-Deployment, schützen Sie den Aufruf also mit #available(iOS 26.0, *), wenn Sie ältere Versionen unterstützen.
Was bedeuten .tight, .normal und .loose?
AttributedString.LineHeight hat vier statische Properties und drei Factory-Methoden. Apples Dokumentation beschreibt jede davon:
| Wert | Apples Beschreibung | Skaliert mit Dynamic Type |
|---|---|---|
.tight | Vielfaches der Punktgröße, das als eng empfunden wird | Ja |
.normal | Vielfaches der Punktgröße, das als normal empfunden wird | Ja |
.loose | Vielfaches der Punktgröße, das als weit empfunden wird | Ja |
.variable | Basiert auf Ober- und Unterlänge der Schriften in jeder Zeile | Ja |
.multiple(factor:) | Größte Punktgröße multipliziert mit factor | Ja |
.leading(increase:) | Größte Punktgröße plus increase Punkte | Teilweise: Die Schrift wächst, der Zuschlag nicht |
.exact(points:) | Eine feste Gesamthöhe in Punkten | Nein |
Apple veröffentlicht die Zahlen hinter den drei Presets nicht. Laut @sarunw sind sie Abkürzungen für .multiple(factor:): .tight ist 1.0, .normal 1.2 und .loose 1.5. Wenn Sie einen bestimmten Wert brauchen, schreiben Sie den Faktor selbst, damit Ihr Code nicht von dieser Zuordnung abhängt.
Der Vergleich von Nil Coalescing ergab, dass .normal und .variable kaum vom Standard zu unterscheiden sind. Der Unterschied liegt in der Definition: .variable folgt den Schriftmetriken jeder Zeile, während die anderen Werte laut Apple unabhängig von der tatsächlichen Ober- und Unterlänge der verwendeten Schriften konstant sind.
Wie verhält sich .multiple(factor:) zu CSS line-height?
Wenn Sie aus dem Web kommen, ist .multiple(factor:) der Wert, den Sie suchen. Wie @sarunw es formuliert, funktioniert .lineHeight(.multiple(factor: 1.5)) wie CSS line-height: 1.5: Die Zeilenhöhe ist die Schriftgröße mal dem Faktor.
Apples Definition sagt dasselbe, mit einem Detail: Der Faktor multipliziert die größte Punktgröße in der Zeile. Eine Zeile, die einen Fließtext mit 17 pt und eine eingebettete Phrase mit 22 pt mischt, verwendet also 22 pt.
Text(article.body)
.font(.body)
.lineHeight(.multiple(factor: 1.5))
Weil .body ein Textstil ist, ändert sich die Punktgröße mit der Dynamic-Type-Einstellung der Person, und die Zeilenhöhe ändert sich mit. Nil Coalescing bestätigt, dass multiple(factor:) die Abstände über alle Dynamic-Type-Größen proportional hält.
Die beiden anderen Methoden tauschen diese Flexibilität gegen Kontrolle:
Text(caption)
.lineHeight(.leading(increase: 6))
Text(ticketNumber)
.lineHeight(.exact(points: 24))
.leading(increase:) ist die größte Punktgröße plus eine feste Anzahl Punkte, der Abstand bleibt also gleich, wenn die Schrift wächst. .exact(points:) ignoriert die Schrift vollständig. Nil Coalescing warnt, dass sich Zeilen mit einem exakten Wert bei größeren Textgrößen überlappen oder abgeschnitten werden können. Verwenden Sie ihn also, wenn überhaupt, nur für kurzen Text mit fester Größe.
Warum sitzt ein einzeiliges Label mit lineHeight zu hoch?
Das ist der Haken. Ein Browser teilt den zusätzlichen Platz einer CSS-Zeilenhöhe in zwei Hälften über und unter dem Text auf; die CSS-Spezifikation nennt das Half-Leading. Laut @sarunw setzt .lineHeight in SwiftUI den gesamten zusätzlichen Platz unter jede Zeile, auch wenn es nur eine gibt. Ein einzeiliges Label mit .multiple(factor: 2) wirkt deshalb, als säße es zu hoch.
In einem Absatz ist das harmlos: Der Platz landet zwischen den Zeilen, und genau das wollten Sie. In einem einzeiligen Label in einem Button, einem Chip oder einer zentrierten Zeile sitzt der Text dagegen oben in einem höheren Frame, und das Zentrieren des Frames zentriert nicht den Text.
Einige Wege, damit umzugehen:
- Begrenzen Sie den Modifier. Da
.lineHeightüber das Environment wirkt, wenden Sie ihn auf den Absatz-Textan, nicht auf den ganzen Screen. Setzt eine übergeordnete View ihn, setzen Sie ein Label mit.lineHeight(nil)zurück. - Richten Sie an Grundlinien aus. Verwenden Sie in einer Zeile
HStack(alignment: .firstTextBaseline)oder.lastTextBaseline, damit Labels an ihrem Text ausgerichtet werden, nicht an ihren Frames, und zusätzlicher Platz unter einer Zeile sie nicht verschiebt. - Halten Sie Faktoren für kurzen Text moderat. Ein großer Faktor hilft vor allem beim Lesen langer Texte. Überschriften und Labels brauchen selten mehr als den Standard.
HStack(alignment: .firstTextBaseline) {
Text(item.title)
.font(.headline)
Spacer()
Text(item.price, format: .currency(code: "USD"))
.font(.subheadline)
}
.lineHeight(nil)
Hier ignoriert die Zeile jede weiter oben gesetzte Zeilenhöhe, und die beiden Labels werden an ihrer ersten Grundlinie ausgerichtet. Testen Sie beides mit großen Dynamic-Type-Größen, denn dort zeigen sich Abstandsprobleme zuerst.
Was ist der Unterschied zwischen lineHeight, lineSpacing und leading?
SwiftUI bietet jetzt drei Wege, den Abstand zwischen Zeilen zu ändern, und sie messen Unterschiedliches:
| API | Seit | Was sie festlegt | Einheit |
|---|---|---|---|
.lineHeight(_:) | iOS 26 | Grundlinie zu Grundlinie | Faktor oder Punkte |
.lineSpacing(_:) | iOS 13 | Unteres Ende einer Zeile bis oberes Ende der nächsten | Punkte |
Font.leading(_:) | iOS 14 | Der eigene Zeilenabstand der Schrift | .standard, .loose, .tight |
lineSpacing(_:) fügt einen festen Abstand zwischen Zeilen ein. Das ist nützlich, lässt sich aber nicht auf eine Designvorgabe abbilden, die die Zeilenhöhe als Vielfaches angibt, und der Abstand wächst nicht mit Dynamic Type. Apples Beispiel verwendet .lineSpacing(10).
Font.leading(_:) wird auf eine Schrift angewendet, etwa .font(.title.leading(.loose)). Apple weist darauf hin, dass die Verfügbarkeit von Leading-Anpassungen von der Schrift abhängt, und bei manchen Schriften hat der Modifier keine Wirkung. Nil Coalescing beschreibt seinen Effekt als sehr subtil.
Für neuen Code ab iOS 26 ist .lineHeight die API, die der Art entspricht, wie Designer Text spezifizieren. Behalten Sie .lineSpacing für ältere Deployment Targets.
Wie lasse ich Zahlen mit contentTransition(.numericText()) rollen?
Ein verwandter Texteffekt, der häufig für Punktestände, Zähler und Preise gewünscht wird: @sarunw weist darauf hin, dass .contentTransition(.numericText()) Zahlen zu ihrem neuen Wert rollen lässt. Statt zu überblenden, gleitet jede sich ändernde Ziffer zu ihrem neuen Wert.
struct ScoreView: View {
@State private var score = 0
var body: some View {
VStack {
Text(score, format: .number)
.font(.largeTitle.monospacedDigit())
.contentTransition(.numericText(value: Double(score)))
Button("Add 10") {
withAnimation { score += 10 }
}
}
}
}
Zwei Details sorgen dafür, dass es funktioniert. Erstens sagt Apples Hinweis zu contentTransition(_:), dass es nur innerhalb einer Animation wirkt, ändern Sie den Wert also innerhalb von withAnimation. Zweitens nutzt numericText(value:) aus iOS 17 die Differenz zwischen altem und neuem Wert, um die Richtung zu wählen. Das ältere numericText(countsDown:) aus iOS 16 nimmt die Richtung stattdessen als Boolean entgegen.
Die Schrift mit .monospacedDigit() hält die Breite der Zahl stabil, während sich Ziffern ändern. Für animierte Symbole neben Ihren Zahlen lesen Sie unseren Leitfaden zu SF Symbols Animationen und Rendering-Modi.
Ist die Zeilenhöhe auf dem iPhone Duo wichtiger?
Auf dem iPhone Duo meldet das innere Display wie ein iPad eine reguläre Breite, während sich das äußere Display wie andere iPhones verhält (siehe unseren Leitfaden zu den Size Classes des iPhone Duo). Eine Leseansicht, die sich über das innere Display erstreckt, kann deutlich längere Zeilen haben als auf dem äußeren.
Längere Zeilen lesen sich meist besser mit etwas mehr Zeilenhöhe, und ein Wert, der auf dem äußeren Display stimmt, kann sich auf dem inneren gedrängt anfühlen. Weil .lineHeight ein Environment-Wert ist, können Sie ihn an die Size Class koppeln:
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
var body: some View {
Text(article.body)
.font(.body)
.lineHeight(.multiple(factor: horizontalSizeClass == .regular ? 1.5 : 1.3))
.frame(maxWidth: 680)
}
Die Faktoren hier sind Beispiele, keine Empfehlung von Apple. Die Breite mit frame(maxWidth:) zu begrenzen hilft oft mehr als jede Zeilenhöhe, weil es die Zeilenlänge auf dem breiteren Display angenehm hält.
Das Wichtigste in Kürze
- iOS 26 ergänzt
.lineHeight(_:), das einAttributedString.LineHeightentgegennimmt und über das Environment wirkt.nilbedeutet automatisch. .multiple(factor: 1.5)funktioniert wie CSSline-height: 1.5und skaliert mit Dynamic Type. Laut @sarunw entsprechen.tight,.normalund.looseden Faktoren 1.0, 1.2 und 1.5..leading(increase:)addiert feste Punkte;.exact(points:)skaliert nicht und kann bei großen Größen abschneiden.- Der gesamte zusätzliche Platz landet unter jeder Zeile, daher wirken einzeilige Labels zu hoch. Begrenzen Sie den Modifier, und richten Sie Zeilen an Text-Grundlinien aus.
.lineHeightmisst von Grundlinie zu Grundlinie;.lineSpacingfügt einen Abstand zwischen Zeilen ein;Font.leadingbietet drei feine Stufen.- Für rollende Zahlen verwenden Sie
.contentTransition(.numericText(value:))innerhalb vonwithAnimation.
Lesen Sie als Nächstes, wie iOS 27 Drag-to-Reorder und Swipe Actions in SwiftUI handhabt, oder entdecken Sie Spiele, die für die Faltung gebaut sind, mit Apps, die sich bereits an die zwei Displays des iPhone Duo anpassen.
Häufige Fragen
Wie setze ich die Zeilenhöhe in SwiftUI?
Wenden Sie ab iOS 26 .lineHeight(_:) auf einen Text oder eine übergeordnete View an, zum Beispiel .lineHeight(.multiple(factor: 1.5)). Der Wert wird über das Environment nach unten weitergegeben. Mit nil stellen Sie die automatische Zeilenhöhe von SwiftUI wieder her.
Welche Werte verwenden .tight, .normal und .loose?
Apple dokumentiert sie als konstante Zeilenhöhen auf Basis eines Vielfachen der Punktgröße, das als eng, normal und weit empfunden wird. Der Entwickler @sarunw berichtet, dass sie .multiple(factor:) mit 1.0, 1.2 und 1.5 entsprechen.
Was ist der Unterschied zwischen lineHeight und lineSpacing in SwiftUI?
lineSpacing(_:) fügt zwischen dem unteren Ende einer Zeile und dem oberen Ende der nächsten Abstand in Punkten ein. lineHeight(_:) legt den Abstand von einer Grundlinie zur nächsten fest, entweder als Vielfaches der Schriftgröße oder als Punktwert.
Skaliert lineHeight in SwiftUI mit Dynamic Type?
multiple(factor:) skaliert, weil es die Punktgröße multipliziert. leading(increase:) wächst mit der Schrift, addiert aber eine feste Anzahl Punkte. exact(points:) ist eine feste Gesamthöhe, skaliert also nicht und kann Text bei großen Schriftgrößen abschneiden oder überlappen lassen.
Warum sitzt mein einzeiliges Label mit lineHeight zu hoch?
Wie @sarunw anmerkt, setzt .lineHeight den gesamten zusätzlichen Platz unter jede Zeile, auch wenn es nur eine Zeile gibt. Verwenden Sie große Faktoren nur für mehrzeiligen Text, und richten Sie einzelne Zeilen an ihrer Grundlinie aus, statt ihre Frames zu zentrieren.
Quellen
- lineHeight(_:) · Apple Developer Documentation
- AttributedString.LineHeight · Apple Developer Documentation
- multiple(factor:) · Apple Developer Documentation
- exact(points:) · Apple Developer Documentation
- leading(increase:) · Apple Developer Documentation
- lineSpacing(_:) · Apple Developer Documentation
- Font.Leading · Apple Developer Documentation
- numericText(value:) · Apple Developer Documentation
- contentTransition(_:) · Apple Developer Documentation
- iOS 26 adds a .lineHeight modifier to SwiftUI · @sarunw on X
- .lineHeight presets .tight, .normal, .loose = .multiple(factor:) 1.0, 1.2, 1.5 · @sarunw on X
- .lineHeight(.multiple(factor: 1.5)) works like CSS line-height: 1.5 · @sarunw on X
- .lineHeight puts all extra space below each line · @sarunw on X
- .contentTransition(.numericText()) makes numbers roll to their new value · @sarunw on X
- Adjusting line height in SwiftUI on iOS 26 · Nil Coalescing
- CSS 2.2: Visual formatting model details (line-height) · W3C
Machen Sie das Scharnier zum Teil Ihrer App.
Wir stellen Apps und Spiele vor, die mit dem iPhone Duo wirklich etwas anfangen. Schicken Sie uns Ihre mit einem Link zum App Store – oder sehen Sie sich an, was andere gebaut haben.