Bu API’leri kendi uygulamalarımda 4 yıl boyunca geliştirdikten sonra, HandySwiftUI’ın ilk etiketli sürümünü paylaşmaktan mutluluk duyuyorum. Bu paket, yalnızca geçen yıl 10 uygulama yayınlamamda büyük rol oynayan çeşitli yardımcı araçlar ve kolaylık API’leri içeriyor. HandySwift paketimin Foundation için sunduğu kolaylıklara benzer şekilde, SwiftUI geliştirme için pratik çözümler sunuyor.
Bu yazıda, TranslateKit, FreemiumKit ve CrossCraft gibi uygulamalarımda günlük geliştirme sürecinde en değerli bulduğum extension’ların bir seçkisini paylaşacağım. HandySwiftUI çok daha fazla yardımcı araç içerse de, bu extension’lar gerçek dünya uygulamalarında defalarca kendini kanıtladı ve senin SwiftUI projelerinde de işine yarayabilir.
Optional Binding Kolaylıkları
?? ve ! operatörleri ile isPresent modifier’ı, binding’lerde optional değerlerle çalışmayı kolaylaştırır:
struct EditableProfile: View {
@State private var profile: Profile?
@State private var showAdvanced = false
var body: some View {
Form {
// `??` operatörü ile optional binding için varsayılan değer sağla
TextField("Name", text: $profile?.name ?? "Anonymous")
// `!` operatörü ile binding değerini tersine çevir
Toggle("Hide Details", isOn: !$showAdvanced)
}
// Sheet sunumu için optional binding kullan
.sheet(isPresented: $profile.isPresent(wrappedType: Profile.self)) {
ProfileEditor(profile: $profile)
}
}
}Bu operatörler, modellerdeki optional verilerle çalışırken her türlü view’da işine yarar.
Renk Yönetimi
Kapsamlı renk extension’ları, renk manipülasyonu ve sistem rengi benimseme için güçlü araçlar sunar:
struct ColorfulView: View {
@State private var baseColor = Color.blue
var body: some View {
VStack {
// Temel rengin varyasyonlarını oluştur
Rectangle()
.fill(baseColor.change(.luminance, by: -0.2))
Rectangle()
.fill(baseColor)
Rectangle()
.fill(baseColor.change(.luminance, by: 0.2))
// Hex renklerle çalış
Circle()
.fill(Color(hex: "#FF5733"))
// Renk bileşenlerini kullan
Text("HSB: \(baseColor.hsbo.hue), \(baseColor.hsbo.saturation), \(baseColor.hsbo.brightness)")
Text("RGB: \(baseColor.rgbo.red), \(baseColor.rgbo.green), \(baseColor.rgbo.blue)")
}
.padding()
// Özel sistem benzeri bileşenler için anlamsal sistem renkleri kullan
.background(Color.systemBackground)
}
}
Renk parlaklığını ayarlarken, HSB renk sistemindeki .brightness yerine .luminance kullan. Luminance, insanların ışık ve karanlığı nasıl algıladığını daha iyi temsil eder. Bu yüzden HandySwiftUI, HLC renk uzayı desteği de içerir.
Zengin Metin Biçimlendirme
Metin biçimlendirme extension’ları, XML tarzı etiketlerden ilham alan karışık stillerle zengin metin oluşturmanın pratik bir yolunu sunar:
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 döndürmek ($0 yerine), eklenen anahtarların mevcut anahtarları geçersiz kılması anlamına gelir
)
}
}
Yukarıdaki örnekte, HandySwiftUI ile birlikte gelen yerleşik .htmlLike stilleme, özel etiketlerle birleştirilmiş. .htmlLike’ın şunu döndürdüğünü not et:
[
"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) },
]/> ile biten XML benzeri girişler – yukarıdaki örnekteki <star.fill/> gibi – SFSymbol olarak render edilir. Bu sayede metin içinde kolayca SFSymbol kullanabilirsin.
Görsel İşleme
UIImage ve NSImage için birleşik görsel işleme extension’ları:
class ImageProcessor {
func processImage(_ image: UIImage) {
// En-boy oranını koruyarak görseli yeniden boyutlandır
let resized = image.resized(maxWidth: 800, maxHeight: 600)
// Farklı formatlara dönüştür
let pngData = image.webpData()
let jpegData = image.webpData(compressionQuality: 0.8)
let heicData = image.heicData(compressionQuality: 0.8)
}
}Bu API’lerin hepsinin, sistemin belleği aşırı düşük olduğu gibi uç durumlar için optional değerler döndürdüğünü not et. Ama çoğu zaman başarılı olurlar.
Pratik Model-View Dönüşümleri
HandySwiftUI, model tiplerini doğrudan SwiftUI view’larında görüntülemeyi kolaylaştıran initializer kolaylıkları sunar:
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()
// Enum case'inden doğrudan sekme öğesi oluştur
.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)
}
// Text ve Image view'larıyla da çalışır
Text(convertible: selectedTab) // Sekme adını gösterir
Image(convertible: selectedTab) // Sekme ikonunu gösterir
}
}Modellerinden string’leri ve sembol adlarını manuel olarak çıkarmak yerine, metin için CustomStringConvertible‘a, SF Symbol’ler için CustomSymbolConvertible‘a veya her ikisi için CustomLabelConvertible‘a uyum sağlayabilirsin. Sonra SwiftUI view’larını doğrudan oluşturmak için pratik initializer’ları kullan:
Text(convertible:)- Herhangi birCustomStringConvertible’dan metin oluştururImage(convertible:)- Herhangi birCustomSymbolConvertible’dan SF Symbol görseli oluştururLabel(convertible:)- Herhangi birCustomLabelConvertible’dan metin+ikon etiketi oluşturur
Bu kalıp, yukarıdaki örnekte gösterildiği gibi, UI durumlarını, menü seçeneklerini veya sekmeleri temsil eden enum’larla özellikle iyi çalışır.
Arama Öneki Vurgulama
HandySwiftUI, arama sonuçlarında eşleşen metni vurgulamanın zarif bir yolunu sunar. Kullanıcılara metnin hangi kısımlarının arama sorgularıyla eşleştiğini kolayca gösterebilirsin:
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
// "go mo" aramasında "Good morning!" içindeki "Go mo" kısmını vurgular
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) }
}
}
Bu vurgulama özelliği, aslında TranslateKit’in menü çubuğundaki “Common Translations” özelliği için geliştirildi. Kullanıcıların onaylanmış çeviriler arasında eşleşen ifadeleri hızlıca fark etmesine yardımcı oluyor. Fonksiyon, arama metnini token’lara ayırır ve eşleşen her öneki vurgular. Şunlar için mükemmel:
Listelerde veya menülerde arama sonucu vurgulama
Görsel geri bildirimli otomatik tamamlama önerileri
Eşleşme bağlamını gösterirken metin koleksiyonlarını filtreleme
Belge önizlemelerinde arama eşleşmelerini daha görünür yapma
Vurgulama varsayılan olarak büyük/küçük harf ve aksan işareti duyarsızdır, ancak vurgulama için kullanılan yerel ayarı ve fontu özelleştirebilirsin. Bu, metnin eşleşen kısımlarını vurgulamak istediğin herhangi bir arama arayüzü için çok yönlü bir araç haline getirir.
Hemen Başla
Bu extension’ları projelerinde benim kadar faydalı bulacağını umuyorum. İyileştirme fikirlerin veya SwiftUI topluluğuna katkı sağlayabilecek ek extension’lar için GitHub’da katkıda bulunmaktan çekinme:
github.comFlineDev / HandySwiftUIHandy SwiftUI features that didn’t make it into SwiftUI (yet)
Bu yazı, HandySwiftUI’ın özelliklerini keşfeden dört makaleden oluşan serinin üçüncüsü. Henüz okumadıysan Yeni Tipler ve View Modifier’lar hakkındaki önceki makalelere göz at ve Stiller hakkındaki son yazıyı takipte kal!

