5 H5: Kleuren en logica
De wijzerplaat staat. Nu moeten de segmenten een kleur krijgen op basis van de stroomprijs. Goedkope stroom is groen, dure stroom is rood. In dit hoofdstuk leer je hoe je keuzes maakt in Swift — met if, switch en enums — en hoe je die logica netjes verpakt in een aparte struct.
5.1 Wat gaan we bouwen?
De EnergyColorMapper: een struct die een prijs ontvangt en een kleur teruggeeft. Na dit hoofdstuk kleurt de wijzerplaat automatisch mee met de echte prijzen.

5.2 Playground-voorbeeld
import SwiftUI
import PlaygroundSupport
// Een eenvoudige kleurmapper
func kleurVoorPrijs(_ prijs: Double) -> Color {
if prijs < 0 {
return .blue // negatieve prijs: stroom leveren loont
} else if prijs < 0.10 {
return .green // goedkoop
} else if prijs < 0.20 {
return .yellow // gemiddeld
} else if prijs < 0.30 {
return .orange // duur
} else {
return .red // erg duur
}
}
// Test de functie
let testPrijzen: [Double] = [-0.05, 0.05, 0.15, 0.25, 0.40]
for prijs in testPrijzen {
let kleur = kleurVoorPrijs(prijs)
print("Prijs \(prijs): \(kleur)")
}5.3 Concept uitgelegd
5.3.2 Switch: een meerkeuzetoets
Waar if één vraag stelt, bekijkt switch een waarde en vergelijkt die met meerdere mogelijkheden:
switch huidigeKleurModus {
case .absoluut:
print("Vaste grenzen gebruiken")
case .relatief:
print("Verhoudingsgewijs kleuren")
}Swift dwingt je om alle gevallen te behandelen. Als je een case vergeet, geeft de compiler een foutmelding. Dat is handig: later als je een nieuwe case aan de enum toevoegt, wijst Swift je automatisch op alle plekken in de code die je moet aanpassen.
5.3.3 Drempelwaarden: wanneer wordt iets rood?
In de absoluut-modus werken we met drempelwaarden: vaste euro-bedragen die bepalen welke kleur een prijs krijgt.
prijs < 0 → blauw (negatief: je krijgt geld!)
prijs < €0,10 → groen
prijs < €0,20 → geel
prijs < €0,30 → oranje
prijs >= €0,30 → rood
5.4 Code schrijven
Stap 1: de ColorMode enum
Maak een nieuw bestand ColorMode.swift:
import Foundation
// Bron: EnergyClock/ColorMode.swift
// Bepaalt hoe prijzen worden omgezet naar kleuren
enum ColorMode: String, CaseIterable, Identifiable {
case absolute = "Absoluut"
case relative = "Relatief"
var id: String { rawValue }
}CaseIterable zorgt dat Swift automatisch een lijst kan maken van alle gevallen. Identifiable maakt de enum bruikbaar in een SwiftUI ForEach.
Stap 2: de EnergyColorMapper struct
Maak een nieuw bestand EnergyColorMapper.swift:
import SwiftUI
// Bron: EnergyClock/EnergyColorMapper.swift
// Mapped prijzen naar kleuren op basis van de gekozen kleurmodus
struct EnergyColorMapper {
let prices: [EnergyPrice]
let mode: ColorMode
let absoluteThresholds: AbsoluteThresholds
// Vaste drempelwaarden in EUR/kWh
struct AbsoluteThresholds {
var greenMax: Double // standaard 0.10
var yellowMax: Double // standaard 0.20
var orangeMax: Double // standaard 0.30
}
// Geef de kleur voor een specifiek uur
func color(for hour: Int) -> Color {
guard let priceData = prices.first(where: { $0.hour == hour }),
let price = priceData.price else {
return .gray // geen data beschikbaar
}
return colorForPrice(price)
}
private func colorForPrice(_ price: Double) -> Color {
if price < 0 {
return .blue
}
switch mode {
case .absolute:
return absoluteColor(for: price)
case .relative:
return .gray // relatieve modus volgt in H8
}
}
private func absoluteColor(for price: Double) -> Color {
if price < absoluteThresholds.greenMax {
return .green
} else if price < absoluteThresholds.yellowMax {
return .yellow
} else if price < absoluteThresholds.orangeMax {
return .orange
} else {
return .red
}
}
}Stap 3: de kleurmapper koppelen aan de wijzerplaat
Pas KlokView aan om de mapper te gebruiken:
struct KlokView: View {
let colorMapper: EnergyColorMapper
var body: some View {
Canvas { context, size in
let middelpunt = CGPoint(x: size.width / 2, y: size.height / 2)
let straal = (min(size.width, size.height) / 2) - 20
tekenSegmenten(context: context, middelpunt: middelpunt, straal: straal)
}
.frame(width: 300, height: 300)
}
private func tekenSegmenten(context: GraphicsContext, middelpunt: CGPoint, straal: CGFloat) {
for uur in 0..<24 {
let beginGraden = Double(uur) * 360.0 / 24.0 - 90
let eindGraden = Double(uur + 1) * 360.0 / 24.0 - 90 - 2
var pad = Path()
pad.addArc(
center: middelpunt,
radius: straal,
startAngle: .degrees(beginGraden),
endAngle: .degrees(eindGraden),
clockwise: false
)
// Kleur komt nu uit de mapper
let kleur = colorMapper.color(for: uur)
context.stroke(pad, with: .color(kleur), lineWidth: 16)
}
}
}In dit hoofdstuk gebruiken we een eenvoudige enum met twee cases. Swift-enums kunnen echter ook geassocieerde waarden hebben: extra informatie die per case verschilt.
enum Prijs {
case bekend(Double) // een bedrag
case onbekend // geen data
case negatief(Double) // je krijgt geld terug
}Dit maakt enums veel expressiever dan de simpele lijsten uit andere talen. Samen met switch en pattern matching vormen ze een krachtig systeem om alle mogelijke toestanden van een waarde te beschrijven en af te handelen — zonder dat je ooit een geval kunt missen.
Dit concept, waarbij je de shape van data beschrijft met types in plaats van met conditionals, heet algebraic data types in de taaltheorie.
5.5 Apple documentatie
Meer over enums in Swift:
Meer over switch en pattern matching:
Zoek in de documentatie naar het hoofdstuk “Switch”. Let op het stuk over “Exhaustiveness” — dat legt uit waarom Swift je dwingt alle gevallen te behandelen.
5.6 Samenvatting
| Begrip | Betekenis |
|---|---|
enum |
Een type met een vaste set keuzes |
switch |
Vergelijkt een waarde met meerdere gevallen |
CaseIterable |
Protocol: Swift maakt automatisch een lijst van alle cases |
Identifiable |
Protocol: elke instantie heeft een unieke id |
| Drempelwaarde | Een grenswaarde die bepaalt welke categorie iets valt |
guard let |
Controleert een optional; springt uit de functie als hij leeg is |
5.7 Opdracht
Pas de EnergyColorMapper aan:
- Voeg een vierde drempelwaarde toe: alles onder
0.05wordt cyan (superveel goedkoop). Test dit met een prijs van0.03. - Maak een kleine testfunctie in een Playground die voor de prijzen
[-0.1, 0.03, 0.08, 0.15, 0.25, 0.35]de kleur afdrukt metprint().