İçeriğe geç

HandySwiftUI Extension'lar: SwiftUI Geliştirmeyi Daha Pratik Hale Getirmek

Temiz optional binding'ler, sezgisel renk yönetimi, XML tarzı metin biçimlendirme ve daha fazlası için güçlü SwiftUI extension'larını keşfet. Savaş meydanında test edilmiş bu yardımcı araçlar, uygulamalarındaki kalıp kodları azaltırken daha zarif SwiftUI kodu yazmana yardımcı olacak.

HandySwiftUI Extension'lar: SwiftUI Geliştirmeyi Daha Pratik Hale Getirmek

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)
   }
}

Colorful view

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
       )
   }
}

Formatted text

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 bir CustomStringConvertible’dan metin oluşturur

  • Image(convertible:) - Herhangi bir CustomSymbolConvertible’dan SF Symbol görseli oluşturur

  • Label(convertible:) - Herhangi bir CustomLabelConvertible’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) }
    }
}

Common translations

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!

Bu yazıyı beğendin mi? Swift ipuçları ve indie geliştirici güncellemeleri için Bluesky ve Mastodon üzerinden takip et.