Nach 4 Jahren Feinschliff an diesen APIs in meinen eigenen Apps freue ich mich, das erste getaggte Release von HandySwiftUI zu teilen. Dieses Paket enthält verschiedene Hilfsfunktionen und Convenience-APIs, die mir enorm dabei geholfen haben, allein im letzten Jahr 10 Apps auszuliefern. Es bietet Komfortfunktionen für die SwiftUI-Entwicklung, ähnlich wie mein HandySwift-Paket für Foundation.
In diesem Artikel stelle ich eine Auswahl der Extensions vor, die sich in meiner täglichen Arbeit an Apps wie TranslateKit, FreemiumKit und CrossCraft am meisten bewährt haben. HandySwiftUI enthält zwar noch viele weitere Hilfsfunktionen, aber diese Extensions haben sich in der Praxis immer wieder als besonders wertvoll erwiesen und könnten auch für deine SwiftUI-Projekte nützlich sein.
Komfortfunktionen für optionale Bindings
Die Operatoren ?? und ! sowie der isPresent-Modifier vereinfachen die Arbeit mit optionalen Werten in Bindings:
struct EditableProfile: View {
@State private var profile: Profile?
@State private var showAdvanced = false
var body: some View {
Form {
// Standardwert für optionales Binding über den `??`-Operator
TextField("Name", text: $profile?.name ?? "Anonymous")
// Binding-Wert mit `!`-Operator negieren
Toggle("Hide Details", isOn: !$showAdvanced)
}
// Optionales Binding für Sheet-Präsentation nutzen
.sheet(isPresented: $profile.isPresent(wrappedType: Profile.self)) {
ProfileEditor(profile: $profile)
}
}
}Die Operatoren sind in allen möglichen Views nützlich, wenn du zum Beispiel mit optionalen Daten in Models arbeitest.
Farbverwaltung
Die umfassenden Color-Extensions bieten leistungsstarke Werkzeuge zur Farbmanipulation und Nutzung von Systemfarben:
struct ColorfulView: View {
@State private var baseColor = Color.blue
var body: some View {
VStack {
// Variationen der Basisfarbe erzeugen
Rectangle()
.fill(baseColor.change(.luminance, by: -0.2))
Rectangle()
.fill(baseColor)
Rectangle()
.fill(baseColor.change(.luminance, by: 0.2))
// Mit Hex-Farben arbeiten
Circle()
.fill(Color(hex: "#FF5733"))
// Farbkomponenten verwenden
Text("HSB: \(baseColor.hsbo.hue), \(baseColor.hsbo.saturation), \(baseColor.hsbo.brightness)")
Text("RGB: \(baseColor.rgbo.red), \(baseColor.rgbo.green), \(baseColor.rgbo.blue)")
}
.padding()
// Semantische Systemfarben für eigene systemähnliche Komponenten nutzen
.background(Color.systemBackground)
}
}
Wenn du die Helligkeit einer Farbe anpasst, verwende .luminance statt .brightness aus dem HSB-Farbsystem. Luminanz bildet besser ab, wie Menschen Licht und Dunkelheit wahrnehmen – deshalb unterstützt HandySwiftUI auch den HLC-Farbraum.
Rich-Text-Formatierung
Die Textformatierungs-Extensions bieten eine praktische Möglichkeit, Rich Text mit gemischten Styles zu erstellen, inspiriert von XML-artigen Tags:
struct FormattedText: View {
var body: some View {
Text(
format: "A <b>bold</b> new way to <i>style</i> your text with <star.fill/> and <b>mixed</b> <red>formatting</red>.",
partialStyling: Dictionary.htmlLike.merging([
"red": { $0.foregroundColor(.red) },
"star.fill": { $0.foregroundColor(.yellow) }
]) { $1 } // $1 zurückgeben (statt $0) bedeutet, dass hinzugefügte Keys bestehende überschreiben
)
}
}
Im obigen Beispiel wird das mitgelieferte .htmlLike-Styling von HandySwiftUI mit eigenen Tags kombiniert. Beachte, dass .htmlLike einfach Folgendes zurückgibt:
[
"b": { $0.bold() },
"sb": { $0.fontWeight(.semibold) },
"i": { $0.italic() },
"bi": { $0.bold().italic() },
"sbi": { $0.fontWeight(.semibold).italic() },
"del": { $0.strikethrough() },
"ins": { $0.underline() },
"sub": { $0.baselineOffset(-4) },
"sup": { $0.baselineOffset(6) },
]Alle XML-artigen Einträge, die mit /> enden, wie <star.fill/> im Beispiel oben, werden als SFSymbol gerendert. So kannst du SFSymbols ganz einfach direkt in deinem Text verwenden.
Bildverarbeitung
Einheitliche Extensions für die Bildverarbeitung mit UIImage und NSImage:
class ImageProcessor {
func processImage(_ image: UIImage) {
// Bild unter Beibehaltung des Seitenverhältnisses skalieren
let resized = image.resized(maxWidth: 800, maxHeight: 600)
// In verschiedene Formate konvertieren
let pngData = image.webpData()
let jpegData = image.webpData(compressionQuality: 0.8)
let heicData = image.heicData(compressionQuality: 0.8)
}
}Beachte, dass all diese APIs optionale Werte zurückgeben – für Grenzfälle wie extrem niedrigen Speicher – aber in den meisten Fällen erfolgreich durchlaufen.
Komfortable Model-zu-View-Konvertierungen
HandySwiftUI bietet Initializer-Komfortfunktionen, die es einfach machen, deine Model-Typen direkt in SwiftUI-Views darzustellen:
enum Tab: CustomLabelConvertible {
case home, profile, settings
var description: String {
switch self {
case .home: "Home"
case .profile: "Profile"
case .settings: "Settings"
}
}
var symbolName: String {
switch self {
case .home: "house.fill"
case .profile: "person.circle"
case .settings: "gear"
}
}
}
struct ContentView: View {
@State private var selectedTab: Tab = .home
var body: some View {
TabView(selection: $selectedTab) {
HomeView()
// Tab-Item direkt aus Enum-Case erstellen
.tabItem { Label(convertible: Tab.home) }
.tag(Tab.home)
ProfileView()
.tabItem { Label(convertible: Tab.profile) }
.tag(Tab.profile)
SettingsView()
.tabItem { Label(convertible: Tab.settings) }
.tag(Tab.settings)
}
// Funktioniert auch mit Text- und Image-Views
Text(convertible: selectedTab) // Zeigt den Tab-Namen
Image(convertible: selectedTab) // Zeigt das Tab-Icon
}
}Statt manuell Strings und Symbolnamen aus deinen Models zu extrahieren, kannst du sie auf CustomStringConvertible für Text, CustomSymbolConvertible für SF Symbols oder CustomLabelConvertible für beides konformieren. Dann nutze die komfortablen Initializer, um SwiftUI-Views direkt zu erstellen:
Text(convertible:)– Erstellt Text aus jedemCustomStringConvertibleImage(convertible:)– Erstellt SF-Symbol-Bilder aus jedemCustomSymbolConvertibleLabel(convertible:)– Erstellt Text+Icon-Labels aus jedemCustomLabelConvertible
Dieses Muster funktioniert besonders gut mit Enums, die UI-Zustände, Menüoptionen oder Tabs repräsentieren, wie im Beispiel oben gezeigt.
Suchprefix-Hervorhebung
HandySwiftUI bietet eine elegante Möglichkeit, übereinstimmenden Text in Suchergebnissen hervorzuheben, damit Nutzer sofort sehen, welche Teile des Textes zu ihrer Suchanfrage passen:
struct SearchResultsView: View {
@State private var searchText = ""
let translations = [
"Good morning!",
"Good evening!",
"How are you?",
"Thank you very much!"
]
var body: some View {
List {
ForEach(translations.filtered(by: searchText), id: \.self) { translation in
// Bei Suche nach "go mo" wird "Go mo" in "Good morning!" hervorgehoben
Text(translation.highlightMatchingTokenizedPrefixes(in: searchText))
}
}
.searchable(text: $searchText)
}
}
extension [String] {
func filtered(by searchText: String) -> [String] {
guard !searchText.isEmpty else { return Array(self) }
return filter { $0.localizedCaseInsensitiveContains(searchText) }
}
}
Diese Hervorhebungsfunktion wurde ursprünglich für das „Common Translations”-Feature in der Menüleiste von TranslateKit entwickelt, wo sie Nutzern hilft, passende Phrasen in bestätigten Übersetzungen schnell zu erkennen. Die Funktion zerlegt den Suchtext in Tokens und hebt jeden passenden Prefix hervor – perfekt für:
Hervorhebung von Suchergebnissen in Listen oder Menüs
Autocomplete-Vorschläge mit visuellem Feedback
Filtern durch Textsammlungen mit sichtbarem Trefferkontext
Bessere Sichtbarkeit von Suchtreffern in Dokumentvorschauen
Die Hervorhebung ist standardmäßig case-insensitive und diakritik-insensitive, aber du kannst die Locale und den Font für die Hervorhebung anpassen. Das macht sie zu einem vielseitigen Werkzeug für jede Suchoberfläche, in der du übereinstimmende Textabschnitte betonen möchtest.
Leg noch heute los
Ich hoffe, du findest diese Extensions genauso nützlich in deinen Projekten wie ich in meinen. Wenn du Ideen für Verbesserungen oder zusätzliche Extensions hast, die der SwiftUI-Community zugutekommen könnten, trage gerne auf GitHub bei:
github.comFlineDev / HandySwiftUIHandy SwiftUI features that didn’t make it into SwiftUI (yet)
Dies ist der dritte von vier Artikeln, die die Features von HandySwiftUI erkunden. Schau dir die vorherigen Artikel über Neue Typen und View Modifier an, falls du sie noch nicht gelesen hast, und bleib dran für den letzten Beitrag über Styles!

