İçindekiler
- Problem
- Tasarım kararları ve alternatifler
- Ters giden şey: hiçbir şeyi test etmeyen yeşil kontroller
- Kullanım
- Sınırlar
Problem
SwiftUI'ın Liquid Glass API'si glassEffect yalnız iOS, macOS, tvOS ve watchOS 26'da var.
Kullanıcılarının bir kısmı hâlâ iOS 17 ya da 18'de olan bir uygulamanın iki seçeneği kalıyor: glass
görünümünü yalnız OS 26 kullanıcılarına göstermek ya da her glass görünümünü
if #available(iOS 26, *) dalına alıp else kısmına elle bir alternatif yazmak. İkinci yol aynı
kararı bütün ekranlara dağıtıyor ve her kopya zamanla farklılaşıyor: bir kart temayı unutuyor,
bir diğeri Reduce Transparency'yi yok sayıyor.
LiquidGlassKit bu kararı tek bir yere topluyor. OS 26'da SwiftUI'ın native glassEffect'iyle
çiziyor; daha eski sürümlerde (iOS 17, macOS 14, tvOS 17 ve watchOS 10'a kadar) ve visionOS'ta
tint, kenar highlight'ı ve gölgeyle bir Material blur çiziyor. Her OS için aynı kodu
yazıyorsunuz. Paketin üçüncü taraf bağımlılığı yok ve yalnız Swift Package Manager ile dağıtılıyor.
Tasarım kararları ve alternatifler
Tek giriş noktası. SwiftUI'ın glass API'sini yalnız Surface klasörü çağırıyor:
glassSurface(_:in:interactive:) modifier'ı ve native path'te GlassEffectContainer'ı saran
GlassGroup. Bütün bileşenler (butonlar, kartlar, metin alanları, arama çubuğu, tab bar,
navigation bar, sheet ve 2.1.0'dan beri switch ile slider) glassSurface üzerinden çiziliyor.
Alternatif, her bileşende ayrı bir #available dalıydı. Şubat 2026 kodunda ortak bir yol yoktu:
her bileşen kendi Material dolgusunu çiziyordu (.fill(material.swiftUIMaterial)) ve 2.0.0
changelog'u sonucunu kaydediyor: temayı okumayan bileşenler. Tek giriş noktasının bedeli de var:
bileşene özel bir görünüm, örneğin butonlar için farklı bir gölge, ortak modifier'a yeni bir
parametre eklemeyi gerektiriyor.
SwiftUI'ın adlarından uzak durmak. Şubat kodu kendi glassEffect(_:) ve
GlassEffectContainer tanımlarını içeriyordu. OS 26 SDK'sında bu adlar SwiftUI'ınkilerle
çakışıyor; iki modülü birlikte import eden dosyada çağrılar belirsizleşiyor. Yeniden kurulan API
glassSurface, GlassGroup ve LiquidGlassButtonStyle adlarını kullanıyor (SwiftUI'da zaten bir
GlassButtonStyle var). Kullanıcı Apple'ın adları yerine paketin adlarını öğreniyor; README ve
DocC kataloğu her birinin hangi SwiftUI API'sini sardığını yazıyor.
Rendering path'i üç katmanda seçmek. #if os(visionOS) native çağrıyı derleme anında
kaldırıyor, çünkü SwiftUI glassEffect'i orada unavailable işaretliyor. Çalışma anındaki
#available(iOS 26, macOS 26, tvOS 26, watchOS 26, *) kontrolü aynı binary'nin hem iOS 17'de hem
iOS 26'da çalışmasını sağlıyor. Bunun üstünde GlassRenderingMode (automatic ya da fallback)
environment'tan geliyor; uygulama tutarlı bir görünüm için yedek path'i zorlayabiliyor. Kararın
kendisi saf bir fonksiyon, resolved(nativeAvailable:), ve dört kombinasyonun hepsi testli. İlk
tasarımda bir .native case'i de vardı; 2.0.0'dan önce kaldırıldı (6293c16), çünkü her durumda
.automatic gibi davranıyordu: native glass olmayan yerde zorlanamaz, olan yerde .automatic
zaten onu kullanır.
Şekiller için enum. GlassShape generic bir Shape değil, bir enum (yuvarlak köşeli
dikdörtgen, capsule, daire, köşe başına yarıçap). Böylece GlassTheme içinde saklanabiliyor,
testlerde Hashable olarak karşılaştırılabiliyor ve Swift 6'da Sendable oluyor. Çizim
AnyShape üzerinden yapılıyor. Ödünleşim gerçek: kendi şeklinizi veremiyorsunuz.
Özel view yerine stil. Butonlar bir ButtonStyle (.buttonStyle(.liquidGlass)), switch bir
ToggleStyle (.toggleStyle(.liquidGlass)). Basılı durum configuration.isPressed'den geliyor;
klavye ve VoiceOver davranışı normal bir SwiftUI Button ya da Toggle ile aynı kalıyor.
GlassButton aynı stili kullanan bir kolaylık view'ı olarak duruyor.
Kopyalayarak değil, yeniden yazarak birleştirmek. 2.1.0 sürümü aynı yazara ait, MIT lisanslı
iki eski repodan, LiquidGlass-Playground ve GlassmorphismUI'dan fikirler alıyor. Bu repoların kodu
kendi Material katmanlarını çiziyor, haptics ve erişilebilirlik kontrolleri için UIKit'e
bağlanıyordu. Dosyaları kopyalamak yerine her özellik (switch, slider, gradient glass,
highlight'lar, hazır temalar, kod dışa aktarıcı, tab badge'leri) glassSurface üstüne yeniden
yazıldı; böylece temayı, rendering mode'u ve Reduce Transparency'yi kendiliğinden alıyor. Bazı
özellikler bilerek dışarıda kaldı: blur radius, refraction ve saturation değerlerinin native glass'ta
karşılığı yok. swift package diagnose-api-breaking-changes v2.0.0 kırıcı değişiklik bildirmiyor,
bu yüzden sürüm minor. İki kaynak repo artık arşivde ve buraya yönlendiriyor.
Ters giden şey: hiçbir şeyi test etmeyen yeşil kontroller
Reponun geçmişi düz bir çizgi değil ve changelog bunu açıkça yazıyor. Şubat 2026'daki v1.0.0
tag'i derlenmeyen ilk commit'i gösteriyor. Haziran 2026'da kaynağın çoğu yer tutucularla
değiştirildi, test target'ı var olmayan tiplere başvuruyordu ve test ile lint adımlarında
continue-on-error olduğu için CI yine yeşil görünüyordu. 2.0.0 paketi yeniden kurdu ve bu
ayarı kaldırdı; bugün repodaki hiçbir workflow bunu kullanmıyor.
Asıl faydalı ders, yeniden kurulumdan sonra, yeni testler zaten yeşilken geldi. Kaynaktan
özellikleri tek tek silmek, suite'in bunu fark etmediğini gösterdi. 36ef829 commit'i durumu
anlatıyor: sheet testi yalnız görüntü genişliğini frame genişliğiyle karşılaştırıyordu, oysa bu
genişliği zaten frame veriyor. GlassCard ya da GlassTabBar'dan glass'ı kaldırmak, kartın
material'ını yok saymak ya da koyu glass butonlardaki etiketleri yeniden siyah çizmek suite'i yeşil
bırakıyordu. Testler piksel sayımına çevrildi. Görünümler beyaz bir canvas üzerinde yeşil temayla
çiziliyor ve her bileşen yedek path'te en az 250 yeşil piksel çizmek zorunda; açıkça verilen mavi
material yeşil temayı ezmeli. Tasarımı iki ImageRenderer tuhaflığı belirledi: macOS 27'de hiçbir
şey çizmeyen bir görünüm önceki render'ı tutan bir buffer döndürebiliyor, yani yalnız şeffaflık
güvenilir bir sinyal değil; metin alanları da kırmızı-sarı bir placeholder olarak çiziliyor, bu
yüzden kırmızı test tint'i olarak kullanılamadı. Değişiklikten sonra commit'te listelenen 11
kaynak mutasyonunun her biri en az bir testi kırıyor.
Native path'te de aynı kör nokta vardı. OS 26'da render testi yalnız bir görüntü dönmesini
bekliyordu. Native view her zaman yedeğini çizecek şekilde değiştirildiğinde 39 testin hepsi yine
geçti. ImageRenderer blur'u yakalamadığı ve native glass'ı OS'a göre farklı çizdiği için tint'e
bakan bir kontrol her yerde çalışamazdı. 29ce746 commit'i bunun yerine her bileşeni iki path'te
render ediyor: aynı görünümün iki yedek render'ı piksel piksel aynı, native render ise yedekten
250'den fazla pikselde farklı olmalı. Commit, bileşen başına macOS 27'de en az 3.857, iOS 26.5 ve
27 simülatörlerinde en az 5.005 farklı piksel ölçüldüğünü kaydediyor.
2.1.0 sırasında bir sorun daha çıktı. Piksel eşitliği testleri kabaca dört tam koşudan birinde
kırılıyordu; biri de swift test --no-parallel ile her seferinde kırılıyordu. 68f94e8 commit'i
iki neden buldu: ImageRenderer görüntüsünü önbelleğe alıyor ve bir görünümün ilk render'ları,
Material kenarları ve glyph'ler oturana kadar sonrakilerden farklı çıkıyor. Test yardımcısı artık
her geçişte yeni bir renderer kullanıyor, sekiz geçişlik bir ısınma yapıyor ve ardışık iki geçiş
eşleşince duruyor; üst sınır 16 geçiş.
Kullanım
Paketi Xcode'da File › Add Package Dependencies… menüsünden
https://github.com/muhittincamdali/LiquidGlassKit.git adresiyle ya da Package.swift üzerinden
ekleyin. README'deki hızlı başlangıç örneği, test target'ında birebir derleniyor:
swift
1import LiquidGlassKit2import SwiftUI3 4struct ContentView: View {5 var body: some View {6 ZStack {7 LinearGradient(colors: [.indigo, .pink], startPoint: .top, endPoint: .bottom)8 .ignoresSafeArea()9 VStack(spacing: 16) {10 GlassCard {11 Label("Hello, glass", systemImage: "sparkles")12 }13 GlassButton("Tap me", systemImage: "hand.tap") {}14 }15 }16 }17}Herhangi bir görünüm tek modifier'la glass üzerine oturuyor:
swift
1import LiquidGlassKit2import SwiftUI3 4struct NowPlayingBadge: View {5 var body: some View {6 Label("Now Playing", systemImage: "music.note")7 .padding()8 .glassSurface(.tinted(.purple), in: .capsule)9 }10}Tema ve rendering mode bütün hiyerarşiye uygulanıyor:
swift
1struct ThemedApp: View {2 var body: some View {3 RootView()4 .glassTheme(GlassTheme(material: .tinted(.indigo), shape: .roundedRectangle(cornerRadius: 12)))5 .glassRenderingMode(.automatic) // or .fallback to use the Material look everywhere6 }7}Hazır bir tema ayarlanıp paketi kullanan Swift koduna dönüştürülebiliyor:
swift
1var theme = GlassPreset.named("Ocean")?.theme ?? .standard2theme.shadowRadius = 43let source = GlassCodeExporter().viewCode(named: "PromoCard", theme: theme)Examples/LiquidGlassDemo içindeki demo uygulaması bir galeri, tab bar'lar, sheet, native ile
yedek path karşılaştırması ve bir temayı ayarlayıp dışa aktarılan kodunu gösteren bir playground
ekranı içeriyor. DocC makaleleri GitHub Pages'te yayında.
Sınırlar
- Son glass görünümü test edilmiyor.
ImageRendererblur'u yakalamıyor, native glass'ı da
ancak kısmen yakalıyor. Testler yedek path'in tint'ini ve kapladığı alanı, native path'in yedekten
farklı çizdiğini ölçüyor; README bunu açıkça yazıyor.
- Cihaz kapsamı. CI suite'i macOS'ta, bir iOS 26 simülatöründe ve yalnız yedek path'in olduğu
bir iOS 18.6 simülatöründe koşturuyor. iOS 17 job'ı ve fiziksel cihazda koşum yok.
- Performans ölçümü yok. Repoda yedek blur ve gölgeler için benchmark ya da profil sonucu
bulunmuyor.
- visionOS yalnız yedek path'i kullanıyor, çünkü SwiftUI orada
glassEffectsunmuyor. GlassSheetbir overlay, sistem sheet'i değil: detent yok, ayrı bir presentation context
yok ve tvOS'ta kullanılamıyor. GlassSlider da tvOS'ta yok.
- Sabit şekiller.
GlassShapedört case'ten oluşuyor; özel şekil desteklenmiyor. - Yerelleştirme.
GlassButton,GlassTabveGlassTextFieldbaşlıklarıStringalıyor ve
olduğu gibi gösteriyor; LocalizedStringKey araması yapılmıyor ve paketin kendi yerelleştirilmiş
metinleri yok.
- Toolchain. Native path OS 26 SDK'sına karşı derlendiği için eski deployment target'larda da
Xcode 26 veya üstü gerekiyor.
Güncel sürüm 2.1.0; README'ye göre sonraki bir sürüm henüz planlanmış değil.
Kaynak kod: github.com/muhittincamdali/LiquidGlassKit

