- TextView.swift
- SwiftUI-examples
- Created by Bastiaan Nelissen on 17/03/2026.
Concepten in dit bestand:
- Text – toont een stuk tekst op het scherm
- Label – combineert een icoontje en een tekst
- .font – lettertype en grootte instellen
- .fontWeight – dikte van het lettertype (thin tot black)
- .fontDesign – lettertype-stijl (default, rounded, serif, monospaced)
- .foregroundColor – kleur van de tekst
- .foregroundStyle – kleur via ShapeStyle (gradient, material, etc.)
- .italic() – schuingedrukte tekst
- .bold() – vetgedrukte tekst
- .underline – onderstreping
- .strikethrough – doorstreepte tekst
- .tracking – spatie tussen letters
- .kerning – fijnere spatie-aanpassing per tekenpaar
- .baselineOffset – verticale verschuiving ten opzichte van de basislijn
- .lineSpacing – ruimte tussen regels
- .lineLimit – maximaal aantal zichtbare regels
- .truncationMode – bepaalt waar tekst wordt afgekapt (...begin, ...middle, ...end)
- .multilineTextAlignment – uitlijning van meerregelige tekst
- .textCase – automatisch hoofd- of kleine letters
- .monospacedDigit – cijfers even breed zodat ze netjes uitlijnen
- .redacted – verberg tekst met een grijze balk (skeleton-stijl)
- .privacySensitive – verberg tekst in screenshots en previews
- .textSelection – laat de gebruiker tekst selecteren en kopieren
- AttributedString – tekst met per-karakter opmaak (vet, kleur, link)
- Text + Text – twee Text-views samenvoegen met de + operator
- ScrollView – maakt de inhoud scrollbaar als die te lang is
- Section – groepeert voorbeelden met een koptekst
import SwiftUI
Hoofdview
struct TextView: View {
var body: some View {
NavigationStack geeft ons een navigatiebalk met een titel.
NavigationStack {
ScrollView zorgt dat alle voorbeelden bereikbaar zijn, ook als ze niet op een enkel scherm passen.
ScrollView {
VStack stapelt alle secties verticaal onder elkaar. alignment: .leading lijnt alles links uit.
VStack(alignment: .leading, spacing: 0) {
sectieGrootte
sectieGewicht
sectieKleur
sectieStijl
sectieDecoratie
sectieSpateing
sectieUitlijning
sectieTruncatie
sectieOpmaakCombinaties
sectieAttributed
sectieLabel
sectieSpeciaal
}
.padding(.bottom, 32)
}
.navigationTitle("Tekst en labels")
.navigationSubtitle("Opmaak en manipulatie")
#if os(iOS)
.navigationBarTitleDisplayMode(.large)
#endif
}
}
Lettergrootte
Een computed property die een sectie teruggeeft. Door elke sectie als eigen property te schrijven blijft 'body' leesbaar.
private var sectieGrootte: some View {
Sectie(titel: "Lettergrootte — .font") {
SwiftUI heeft vaste tekststijlen die meeschalen met de tekstgrootte-instelling van het apparaat (Dynamic Type). Grotere tekst is toegankelijker voor slechtzienden.
Voorbeeld(label: ".largeTitle") {
Text("Grote titel").font(.largeTitle)
}
Voorbeeld(label: ".title") {
Text("Titel").font(.title)
}
Voorbeeld(label: ".title2") {
Text("Titel 2").font(.title2)
}
Voorbeeld(label: ".title3") {
Text("Titel 3").font(.title3)
}
Voorbeeld(label: ".headline") {
Text("Headline").font(.headline)
}
Voorbeeld(label: ".subheadline") {
Text("Subheadline").font(.subheadline)
}
Voorbeeld(label: ".body") {
Text("Body (standaard)").font(.body)
}
Voorbeeld(label: ".callout") {
Text("Callout").font(.callout)
}
Voorbeeld(label: ".footnote") {
Text("Footnote").font(.footnote)
}
Voorbeeld(label: ".caption") {
Text("Caption").font(.caption)
}
Voorbeeld(label: ".caption2") {
Text("Caption 2").font(.caption2)
}
Vaste lettergrootte met .system(size:). Dit schaalt NIET mee met Dynamic Type.
Voorbeeld(label: ".system(size: 28)") {
Text("Vaste grootte 28").font(.system(size: 28))
}
}
}
Letterdikte
private var sectieGewicht: some View {
Sectie(titel: "Letterdikte — .fontWeight") {
fontWeight bepaalt hoe dik de letters zijn. Van dun naar zwaar: ultraLight → thin → light → regular
- → medium → semibold → bold → heavy → black
Voorbeeld(label: ".ultraLight") {
Text("UltraLight").fontWeight(.ultraLight).font(.title3)
}
Voorbeeld(label: ".thin") {
Text("Thin").fontWeight(.thin).font(.title3)
}
Voorbeeld(label: ".light") {
Text("Light").fontWeight(.light).font(.title3)
}
Voorbeeld(label: ".regular") {
Text("Regular").fontWeight(.regular).font(.title3)
}
Voorbeeld(label: ".medium") {
Text("Medium").fontWeight(.medium).font(.title3)
}
Voorbeeld(label: ".semibold") {
Text("Semibold").fontWeight(.semibold).font(.title3)
}
Voorbeeld(label: ".bold") {
Text("Bold").fontWeight(.bold).font(.title3)
}
Voorbeeld(label: ".heavy") {
Text("Heavy").fontWeight(.heavy).font(.title3)
}
Voorbeeld(label: ".black") {
Text("Black").fontWeight(.black).font(.title3)
}
.bold() is een snelkoppeling voor .fontWeight(.bold)
Voorbeeld(label: ".bold() snelkoppeling") {
Text("Vet via .bold()").bold()
}
}
}
Kleur
private var sectieKleur: some View {
Sectie(titel: "Kleur — .foregroundColor / .foregroundStyle") {
.foregroundColor past de tekstkleur aan. De systeemkleuren passen automatisch aan bij licht/donker modus.
Voorbeeld(label: ".primary") {
Text("Primaire tekst").foregroundColor(.primary)
}
Voorbeeld(label: ".secondary") {
Text("Secundaire tekst").foregroundColor(.secondary)
}
Voorbeeld(label: ".accentColor") {
Text("Accentkleur").foregroundColor(.accentColor)
}
Voorbeeld(label: ".red") {
Text("Rood").foregroundColor(.red)
}
Voorbeeld(label: ".orange") {
Text("Oranje").foregroundColor(.orange)
}
Voorbeeld(label: ".green") {
Text("Groen").foregroundColor(.green)
}
Voorbeeld(label: ".blue") {
Text("Blauw").foregroundColor(.blue)
}
Voorbeeld(label: ".purple") {
Text("Paars").foregroundColor(.purple)
}
.foregroundStyle accepteert ook een LinearGradient. Zo krijgt de tekst een verloopkleur.
Voorbeeld(label: "LinearGradient") {
Text("Verloopkleur")
.font(.title2.bold())
.foregroundStyle(
LinearGradient(
colors: [.orange, .pink, .purple],
startPoint: .leading,
endPoint: .trailing
)
)
}
Aangepaste kleur via RGB-waarden (0.0 tot 1.0)
Voorbeeld(label: "Color(red:green:blue:)") {
Text("Eigen kleur")
.foregroundColor(Color(red: 0.2, green: 0.7, blue: 0.5))
}
Kleur met transparantie via .opacity()
Voorbeeld(label: ".opacity(0.4)") {
Text("Half transparant")
.foregroundColor(.blue.opacity(0.4))
.font(.title3)
}
}
}
Stijl en ontwerp
private var sectieStijl: some View {
Sectie(titel: "Lettertypestijl — .fontDesign / .italic()") {
.fontDesign bepaalt de algemene stijl van het systeemlettertype.
Voorbeeld(label: ".default") {
Text("Standaard ontwerp").font(.title3.weight(.medium))
}
Voorbeeld(label: ".rounded") {
Text("Afgerond ontwerp")
.font(.title3.weight(.medium))
.fontDesign(.rounded)
}
Voorbeeld(label: ".serif") {
Text("Serif ontwerp")
.font(.title3.weight(.medium))
.fontDesign(.serif)
}
Voorbeeld(label: ".monospaced") {
Text("Monospaced ontwerp")
.font(.title3.weight(.medium))
.fontDesign(.monospaced)
}
.italic() maakt de tekst cursief.
Voorbeeld(label: ".italic()") {
Text("Cursieve tekst").italic()
}
Combinatie van meerdere stijlen tegelijk
Voorbeeld(label: "Bold + italic + rounded") {
Text("Combinatie")
.font(.title2.bold())
.italic()
.fontDesign(.rounded)
.foregroundColor(.indigo)
}
}
}
Decoratie
private var sectieDecoratie: some View {
Sectie(titel: "Decoratie — underline / strikethrough") {
.underline() tekent een lijn onder de tekst. De kleur is standaard gelijk aan de tekstkleur.
Voorbeeld(label: ".underline()") {
Text("Onderstreepte tekst").underline()
}
Voorbeeld(label: ".underline(color: .red)") {
Text("Rode onderstreping").underline(color: .red)
}
.strikethrough() tekent een lijn door de tekst heen. Handig voor afgeronde of verwijderde items.
Voorbeeld(label: ".strikethrough()") {
Text("Doorgestreepte tekst").strikethrough()
}
Voorbeeld(label: ".strikethrough(color: .orange)") {
Text("Oranje doorstreping")
.strikethrough(color: .orange)
.foregroundColor(.secondary)
}
Combinatie: doorstreping + andere kleur
Voorbeeld(label: "Oud en nieuw naast elkaar") {
HStack(spacing: 8) {
Text("49,99")
.strikethrough()
.foregroundColor(.secondary)
Text("29,99")
.bold()
.foregroundColor(.green)
}
}
}
}
Spatiering
private var sectieSpateing: some View {
Sectie(titel: "Spatiering — tracking / kerning / lineSpacing") {
.tracking voegt gelijkmatige ruimte toe tussen alle letters. Positief = meer ruimte, negatief = minder ruimte.
Voorbeeld(label: ".tracking(-2)") {
Text("Nauw").tracking(-2).font(.title3)
}
Voorbeeld(label: ".tracking(0) standaard") {
Text("Standaard").tracking(0).font(.title3)
}
Voorbeeld(label: ".tracking(6)") {
Text("Wijd").tracking(6).font(.title3)
}
Voorbeeld(label: ".tracking(12)") {
Text("Heel wijd").tracking(12).font(.title3)
}
.kerning is subtieler dan tracking: past de ruimte aan tussen specifieke tekenparen (A-V, T-o, etc.).
Voorbeeld(label: ".kerning(4)") {
Text("Kerning voorbeeld").kerning(4)
}
.baselineOffset verschuift de tekst omhoog (positief) of omlaag (negatief) ten opzichte van de basislijn. Handig voor voet- of superscript-effecten.
Voorbeeld(label: ".baselineOffset") {
HStack(alignment: .bottom, spacing: 0) {
Text("H")
.font(.title)
Text("2")
.font(.caption)
.baselineOffset(-6)
Text("O")
.font(.title)
}
}
.lineSpacing regelt de ruimte tussen regels bij meerregelige tekst.
Voorbeeld(label: ".lineSpacing(2) standaard") {
Text("Eerste regel\nTweede regel\nDerde regel")
.lineSpacing(2)
}
Voorbeeld(label: ".lineSpacing(12)") {
Text("Eerste regel\nTweede regel\nDerde regel")
.lineSpacing(12)
}
}
}
Uitlijning en afkapping
private var sectieUitlijning: some View {
Sectie(titel: "Uitlijning — .multilineTextAlignment") {
.multilineTextAlignment bepaalt hoe meerregelige tekst uitgelijnd is. Let op: dit heeft alleen effect als de Text breder is dan een regel.
Voorbeeld(label: ".leading (links, standaard)") {
Text("Dit is een langere zin die over meerdere regels loopt.")
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity, alignment: .leading)
}
Voorbeeld(label: ".center (gecentreerd)") {
Text("Dit is een langere zin die over meerdere regels loopt.")
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity, alignment: .center)
}
Voorbeeld(label: ".trailing (rechts)") {
Text("Dit is een langere zin die over meerdere regels loopt.")
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
}
Afkapping en regellimiet
private var sectieTruncatie: some View {
Sectie(titel: "Afkapping — .lineLimit / .truncationMode") {
.lineLimit beperkt de tekst tot een aantal regels. De rest wordt afgekapt met een '...'.
Voorbeeld(label: ".lineLimit(1)") {
Text("Dit is een heel lange zin die zeker niet op een regel past maar toch maar een regel mag innemen.")
.lineLimit(1)
}
Voorbeeld(label: ".lineLimit(2)") {
Text("Dit is een heel lange zin die zeker niet op een regel past maar toch maar twee regels mag innemen.")
.lineLimit(2)
}
Voorbeeld(label: ".lineLimit(nil) geen limiet") {
Text("Dit is een heel lange zin die zeker niet op een regel past en alle ruimte mag innemen die hij nodig heeft.")
.lineLimit(nil)
}
.truncationMode bepaalt waar de '...' verschijnt.
Voorbeeld(label: ".truncationMode(.tail) standaard") {
Text("Afkappen aan het einde van de tekst hier")
.lineLimit(1)
.truncationMode(.tail)
}
Voorbeeld(label: ".truncationMode(.middle)") {
Text("Afkappen in het midden van de tekst hier")
.lineLimit(1)
.truncationMode(.middle)
}
Voorbeeld(label: ".truncationMode(.head)") {
Text("Afkappen aan het begin van de tekst hier")
.lineLimit(1)
.truncationMode(.head)
}
.allowsTightening laat SwiftUI de letterafstand iets verkleinen om te voorkomen dat tekst afgekapt wordt.
Voorbeeld(label: ".allowsTightening(true)") {
Text("Iets compacter als het krap is")
.lineLimit(1)
.allowsTightening(true)
}
.minimumScaleFactor schaalt de tekst kleiner als hij niet past. 0.5 betekent: tot de helft van de originele grootte verkleinen.
Voorbeeld(label: ".minimumScaleFactor(0.5)") {
Text("Kleinere tekst als het niet past")
.font(.title)
.lineLimit(1)
.minimumScaleFactor(0.5)
}
}
}
Opmaak combinaties
private var sectieOpmaakCombinaties: some View {
Sectie(titel: "Combinaties") {
.textCase past automatisch hoofd- of kleine letters toe zonder de onderliggende string te wijzigen.
Voorbeeld(label: ".textCase(.uppercase)") {
Text("automatisch hoofdletters").textCase(.uppercase)
}
Voorbeeld(label: ".textCase(.lowercase)") {
Text("AUTOMATISCH KLEINE LETTERS").textCase(.lowercase)
}
.monospacedDigit zorgt dat alle cijfers even breed zijn. Handig bij tellers of tabellen zodat de tekst niet verspringt.
Voorbeeld(label: ".monospacedDigit()") {
VStack(alignment: .trailing, spacing: 4) {
Text("1.234,56").monospacedDigit()
Text("99,00").monospacedDigit()
Text("10.000,10").monospacedDigit()
}
.font(.body)
}
Text + Text combineert twee tekststukken tot een geheel. Elk deel kan zijn eigen opmaak hebben.
Voorbeeld(label: "Text + Text samenvoegen") {
Text("Normaal ")
+ Text("vet ").bold()
+ Text("en ")
+ Text("gekleurd").foregroundColor(.orange)
+ Text(" in een zin.")
}
Opmaak via string-interpolatie met format:
Voorbeeld(label: "Getal met format:") {
VStack(alignment: .leading, spacing: 4) {
Text(1234567.89, format: .number)
Text(1234567.89, format: .currency(code: "EUR"))
Text(0.856, format: .percent)
Text(Date.now, format: .dateTime.day().month().year())
}
.font(.body.monospacedDigit())
}
}
}
AttributedString
private var sectieAttributed: some View {
Sectie(titel: "AttributedString — per-karakter opmaak") {
AttributedString laat je per teken of woord andere opmaak instellen. Dit is de moderne Swift-versie van NSAttributedString.
Voorbeeld(label: "Gemengde opmaak") {
Text(gemaakteAttributedString)
}
Markdown in een String literal wordt automatisch herkend. Ondersteunde opmaak: **vet**, *cursief*, `code`, [link](url)
Voorbeeld(label: "Markdown in Text") {
Text("Dit is **vet**, dit is *cursief* en dit is `code`.")
}
Voorbeeld(label: "Markdown link") {
Text("Bezoek [Apple](https://apple.com) voor meer info.")
}
}
}
Bouw een AttributedString op met verschillende stijlen per woord.
private var gemaakteAttributedString: AttributedString {
var tekst = AttributedString("Groot ")
tekst.font = .title2.bold()
tekst.foregroundColor = .indigo
var normaal = AttributedString("normaal ")
normaal.font = .body
var rood = AttributedString("rood ")
rood.foregroundColor = .red
rood.font = .body.bold()
var onderstreept = AttributedString("onderstreept")
onderstreept.underlineStyle = .single
onderstreept.font = .body
AttributedString-stukken samenvoegen met +=
tekst += normaal
tekst += rood
tekst += onderstreept
return tekst
}
Label
private var sectieLabel: some View {
Sectie(titel: "Label — tekst met icoontje") {
Label combineert een SF Symbol-icoontje met een tekst. Het past zich aan het platform aan: in toolbars toont het soms alleen het icoontje, elders beide.
Voorbeeld(label: "Standaard Label") {
Label("Instellingen", systemImage: "gear")
}
Voorbeeld(label: "Label met kleur") {
Label("Favorieten", systemImage: "star.fill")
.foregroundColor(.orange)
}
Voorbeeld(label: ".labelStyle(.iconOnly)") {
Label("Alleen icoontje", systemImage: "bell.fill")
.labelStyle(.iconOnly)
.foregroundColor(.blue)
}
Voorbeeld(label: ".labelStyle(.titleOnly)") {
Label("Alleen tekst", systemImage: "bell.fill")
.labelStyle(.titleOnly)
}
Voorbeeld(label: ".labelStyle(.titleAndIcon)") {
Label("Tekst en icoontje", systemImage: "heart.fill")
.labelStyle(.titleAndIcon)
.foregroundColor(.red)
}
Label met een eigen view als icoontje
Voorbeeld(label: "Label met eigen icoontje") {
Label {
Text("Eigen icoontje")
.foregroundColor(.primary)
} icon: {
RoundedRectangle(cornerRadius: 4)
.fill(Color.purple)
.frame(width: 20, height: 20)
.overlay(
Text("A")
.font(.caption.bold())
.foregroundColor(.white)
)
}
}
}
}
Speciale modifiers
private var sectieSpeciaal: some View {
Sectie(titel: "Speciale modifiers") {
.redacted(reason: .placeholder) vervangt de tekst met een grijze balk. Handig als laadscherm terwijl data nog opgehaald wordt (skeleton UI).
Voorbeeld(label: ".redacted(.placeholder)") {
VStack(alignment: .leading, spacing: 6) {
Text("Dit is een titel die verborgen is")
.font(.headline)
Text("En dit is een langere beschrijvingstekst")
.font(.body)
.foregroundColor(.secondary)
}
.redacted(reason: .placeholder)
}
.textSelection(.enabled) laat de gebruiker de tekst selecteren door er lang op te drukken (zoals in een browser).
Voorbeeld(label: ".textSelection(.enabled)") {
Text("Druk lang om te selecteren")
.textSelection(.enabled)
}
.privacySensitive() verbergt de tekst in screenshots, app-switcher en andere plaatsen waar privacy belangrijk is.
Voorbeeld(label: ".privacySensitive()") {
Text("Geheime waarde: 1234")
.privacySensitive()
}
Tekst in een Badge toont een getal of label bovenop een icoontje. .badge is een modifier op een List-rij of TabItem.
Voorbeeld(label: "Text als teller badge") {
HStack {
Image(systemName: "envelope.fill")
.font(.title2)
.foregroundColor(.blue)
Text("12")
.font(.caption2.bold())
.foregroundColor(.white)
.padding(.horizontal, 6)
.padding(.vertical, 2)
.background(Color.red)
.clipShape(Capsule())
}
}
}
}
}
Herbruikbare hulpviews
Sectie groepeert een reeks voorbeelden onder een gedeeld koptekst. Generieke parameter 'Content' laat toe dat elk soort View als inhoud meegegeven wordt.
struct Sectie<Content: View>: View {
let titel: String
@ViewBuilder zorgt dat de 'inhoud' closure meerdere views kan teruggeven.
@ViewBuilder let inhoud: () -> Content
var body: some View {
VStack(alignment: .leading, spacing: 0) {
Sectie-koptekst
Text(titel)
.font(.headline)
.foregroundColor(.primary)
.padding(.horizontal, 16)
.padding(.top, 28)
.padding(.bottom, 12)
Scheidingslijn onder de koptekst
Rectangle()
.fill(Color.accentColor.opacity(0.4))
.frame(height: 2)
.padding(.horizontal, 16)
Alle voorbeelden
VStack(alignment: .leading, spacing: 0) {
inhoud()
}
.padding(.top, 4)
}
}
}
Voorbeeld toont een label (de modifier-naam) en het visuele resultaat ernaast.
struct Voorbeeld<Content: View>: View {
let label: String
@ViewBuilder let inhoud: () -> Content
var body: some View {
HStack(alignment: .center, spacing: 12) {
Label: de naam van de modifier, vaste breedte zodat alles uitlijnt.
Text(label)
.font(.system(size: 11, design: .monospaced))
.foregroundColor(.secondary)
.frame(width: 200, alignment: .leading)
.lineLimit(2)
.minimumScaleFactor(0.8)
Divider().frame(height: 32)
Het visuele resultaat van de modifier
inhoud()
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(.horizontal, 16)
.padding(.vertical, 10)
Elke tweede rij een lichte achtergrond voor leesbaarheid. Dit is een vereenvoudiging; in een echte app gebruik je List.
.background(Color.primary.opacity(0.03))
.overlay(
Rectangle()
.fill(Color.primary.opacity(0.06))
.frame(height: 1),
alignment: .bottom
)
}
}
Preview
#Preview {
TextView()
}