# iOS 26 Liquid Glass: SwiftUI Uygulamanızı Yeni Materyal Sistemine Adapte Etme Rehberi
WWDC25'te Apple, iOS 7'den bu yana en büyük tasarım dili değişikliğini duyurdu: Liquid Glass. iOS 26, iPadOS 26, macOS Tahoe, watchOS 26, tvOS 26 ve visionOS 26'yı kapsayan bu tek materyal sistemi, ışığı gerçek zamanlı bükerek (lensing), cihaz hareketine tepki veren speküler vurgularla ve içeriğe göre adapte olan gölgelerle çalışıyor. Xcode 26 SDK ile derlenen her uygulama bu materyali otomatik olarak miras alıyor — isteseniz de istemeseniz de.
Bu yazıda production bir SwiftUI codebase'ini Liquid Glass'a taşırken karşılaştığım somut kararları, API'ları ve tuzakları paylaşıyorum. Spekülasyon yok — sadece Apple'ın resmi dokümantasyonu ve WWDC25 session 323 ("Build a SwiftUI app with the new design") üzerinden doğrulanmış bilgi.
Neden "otomatik" değil de "adaptasyon" gerekiyor
Xcode 26 ile derleyip iOS 26 hedefleyen her uygulama, standart UIKit/SwiftUI kontrollerinde (buton, tab bar, toolbar, navigation bar) Liquid Glass'ı otomatik alır. Sorun şurada: custom çizilmiş kontroller, elle yönetilen toolbar layout'ları ve .background(.ultraThinMaterial) gibi eski materyal hack'leri bu geçişten faydalanmaz — hatta çoğu zaman yeni sistemle çakışıp görsel bozulmalara (çift blur, kontrast kaybı, yanlış köşe yarıçapı) yol açar. Adaptasyon işi, sistemin sizin için yaptığını elle çakıştırmamak ve gerçekten custom olan yüzeyleri (kartlar, floating action button'lar, özel kontrol grupları) yeni API'larla yeniden ifade etmekten ibaret.
glassEffect API ailesi
Temel modifier glassEffect(_:in:), iOS 26.0+ için mevcut ve varsayılan olarak .regular varyantı + Capsule şeklini kullanıyor:
struct FloatingActionButton: View {
var body: some View {
Image(systemName: "plus")
.font(.title2.weight(.semibold))
.frame(width: 56, height: 56)
.glassEffect(.regular.tint(.blue).interactive())
}
}
Üç temel varyant var:
Varyant | Kullanım alanı |
|---|---|
`.regular` | Varsayılan, çoğu buton/kart için |
`.clear` | Medya-ağırlıklı yüzeyler (fotoğraf/video üstü kontroller); altına mutlaka bir dimming layer koyun |
`.identity` | Efekti pasifleştirip yalnız shape/clipping davranışını korur |
.tint(_:) semantik renklendirme ekler, .interactive() ise dokunmaya tepki veren scale/bounce/shimmer davranışını açar. Modifier zincirinde `.glassEffect()` her zaman en sona yazılmalı — önce shape, sonra padding, en son glass.
Pro Tip
Glass, altındaki içeriği örnekleyerek (sample) render olur. Bu yüzden cam camı örnekleyemez — iki glass view'i doğrudan üst üste koyarsanız alt olan doğru şekilde ışık kırmaz. Bitişik/çakışan glass elemanlarını her zaman GlassEffectContainer içine alın.
GlassEffectContainer ve morphing
Birden fazla glass şeklini tek bir yüzeyde birleştirip birbirine morph ettirmek için GlassEffectContainer kullanılıyor. Namespace tabanlı glassEffectID ile elemanlar arası geçiş animasyonu tanımlanabiliyor:
struct ExpandingToolGroup: View {
@Namespace private var glassNamespace
@State private var isExpanded = false
var body: some View {
GlassEffectContainer(spacing: 16) {
HStack(spacing: 16) {
Button(action: { isExpanded.toggle() }) {
Image(systemName: "wand.and.stars")
}
.glassEffect()
.glassEffectID("trigger", in: glassNamespace)
if isExpanded {
Button(action: {}) { Image(systemName: "scissors") }
.glassEffect()
.glassEffectID("crop", in: glassNamespace)
Button(action: {}) { Image(systemName: "slider.horizontal.3") }
.glassEffect()
.glassEffectID("adjust", in: glassNamespace)
}
}
}
}
}
GlassEffectContainer'ı tek bir yerde, ilgili tüm glass view'ları kapsayacak şekilde kullanın. Her butonu ayrı bir container'a sarmak hem morphing animasyonunu kırar hem de gereksiz render maliyeti yaratır — her container kendi compositing pass'ini tetikliyor.
Köşe eş-merkezliliği (concentricity)
Liquid Glass'ın en kolay gözden kaçan detayı köşe yarıçapı. Bir glass yüzeyini bir container (kart, sheet, kenarlık) içine yerleştirdiğinizde, iç köşe yarıçapının dış container'ın köşesiyle eş-merkezli (concentric) olması gerekiyor — yoksa iki eğri birbirini kesip optik olarak "yamuk" bir his veriyor. iOS 26 bunun için yeni bir shape getirdi: ConcentricRectangle. Sabit bir cornerRadius vermek yerine glass shape'ini container'a göre otomatik hizalayabiliyorsunuz:
struct GlassCard<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
.padding(20)
.glassEffect(.regular, in: .rect(cornerRadius: .containerConcentric))
}
}
.rect(cornerRadius: .containerConcentric), köşe yarıçapını dıştaki container'ın shape'inden ve aradaki padding mesafesinden türetiyor. Elle sabit bir cornerRadius: 16 yazmak yerine bunu kullanmak, farklı ekran boyutlarında ve dynamic type ölçeklerinde köşelerin sistem kartlarıyla tutarlı kalmasını sağlıyor. Manuel yarıçap değerleri, Liquid Glass migrasyonunda en sık düzeltilen "küçük ama her yerde" hatalardan biri.
Tab bar ve toolbar davranış değişiklikleri
iOS 26'da TabView ve toolbar'lar yapısal olarak değişti. İki API özellikle production'da öne çıkıyor:
1. `tabBarMinimizeBehavior(_:)` — kullanıcı içeriği aşağı kaydırdıkça tab bar'ın küçülüp yoldan çekilmesini sağlıyor:
TabView {
Tab("Akış", systemImage: "square.stack") { FeedView() }
Tab("Ara", systemImage: "magnifyingglass", role: .search) { SearchView() }
}
.tabBarMinimizeBehavior(.onScrollDown)
2. `role: .search` — arama sekmesini diğerlerinden görsel olarak ayırıp, seçildiğinde bir arama alanına dönüştürüyor. Arama birincil deneyim değilse, searchToolbarBehavior(.minimize) ile arama çubuğunu scroll'da küçük bir ikona indirgeyebilirsiniz.
Toolbar tarafında item'lar artık içeriğin üstünde yüzen bir Liquid Glass yüzeyinde render oluyor ve alttaki içeriğe göre otomatik kontrast ayarlıyor. Elle .background(Color(.systemBackground).opacity(0.8)) gibi manuel toolbar arka planı veren eski kod, yeni sistemle çakışıp çift katmanlı bulanık bir görünüm üretiyor — bu tarz manuel background modifier'ları tamamen kaldırmak gerekiyor.
Geriye dönük uyumluluk stratejisi
Üç senaryo var ve her biri farklı karar gerektiriyor:
1. iOS 26 hedefleyip Liquid Glass'ı benimsemek (önerilen yol)
Yeni tasarım Apple'ın uzun vadeli yönü. #available(iOS 26, *) kontrolleriyle yeni API'ları koşullu kullanın, eski OS'larda eski görünüme düşün:
if #available(iOS 26, *) {
content.glassEffect(.regular.interactive())
} else {
content.background(.ultraThinMaterial, in: Capsule())
}
2. Geçici opt-out: `UIDesignRequiresCompatibility`
Info.plist'e UIDesignRequiresCompatibility = YES eklenirse, standart UIButton gibi sistem kontrolleri eski (pre-iOS 26) görünümünü koruyor. Bu, büyük bir custom design system'i olan uygulamalar için makul bir köprü ama kalıcı çözüm değil — Apple'ın yol haritası bu bayrağı ileride kaldırmayı işaret ediyor, dolayısıyla yalnız migrasyon süresini kazanmak için kullanılmalı, kalıcı mimari karar olarak değil.
3. Custom render katmanı (SwiftUI dışı / cross-platform)
UIKit tabanlı ya da Flutter/React Native gibi cross-platform kontrol çizen katmanlar, sistem seviyesinde Liquid Glass'ı tamamen devre dışı bırakamaz — Apple bu materyali tüm standart pencerelerde sistem seviyesinde zorunlu kılıyor. Yapabileceğiniz tek şey kendi custom-drawn kontrollerinizi opt-out bayrağıyla korumak ve Apple'ın SDK kontrollerine dokunan yüzeylerde yeni davranışı kabul etmek.
Performans ve yaygın hatalar
Production'da gördüğüm en sık üç hata:
- Her satır/hücrede ayrı `glassEffect()` — bir
Listiçindeki her hücreye tek tek glass uygulamak, scroll sırasında ciddi compositing yüküne yol açıyor. Glass'ı yalnız sabit, az sayıdaki floating yüzeylerde (toolbar, FAB, kontrol grubu) kullanın; liste hücrelerinde değil. - `.clear` varyantını dimming layer'sız kullanmak — açık renkli/parlak içerik üzerinde metin kontrastı WCAG eşiklerinin altına düşüyor.
.clearher zaman bir karartma katmanıyla eşleştirilmeli. - Eski `.ultraThinMaterial`/`.regularMaterial` background'ları yeni glass modifier'larıyla aynı view ağacında bırakmak — iki materyal sistemi üst üste binince hem performans hem görsel tutarlılık kayboluyor. Migrasyonda eski materyal background'larını sistematik olarak tarayıp temizlemek gerekiyor.
Migrasyon öncesi/sonrası: somut karşılaştırma
Aşağıdaki tablo, üzerinde çalıştığım bir production codebase'de en sık dokunulan beş yüzeyin eski ve yeni yaklaşımını özetliyor:
Yüzey | iOS 25 ve öncesi | iOS 26 Liquid Glass |
|---|---|---|
Floating action button | `.background(.ultraThinMaterial, in: Circle())` | `.glassEffect(.regular.tint(.blue).interactive())` |
Tab bar | Sabit yükseklik, elle `.toolbarBackground` | `tabBarMinimizeBehavior(.onScrollDown)`, sistem otomatik yönetir |
Arama sekmesi | Ayrı `.searchable` modifier + manuel yerleşim | `Tab(..., role: .search)` + `searchToolbarBehavior(.minimize)` |
Kontrol grubu (crop/adjust/filter) | Ayrı ayrı `Button` + `HStack`, manuel arka plan | Tek `GlassEffectContainer` içinde `glassEffectID` ile morph |
Liste hücresi arka planı | Gerekirse `.regularMaterial` | Değiştirilmez — glass liste hücresine uygulanmaz |
Bu tablo aslında migrasyonun özünü gösteriyor: değişen şey "her yere glass ekle" değil, hangi yüzeylerin sistemin yeni birincil vatandaşı olduğunu tanımak. Liste hücreleri, form satırları gibi yüksek yoğunluklu tekrarlayan içerik glass'ın hedef alanı değil; floating kontroller, toolbar'lar ve tab bar'lar hedef alan.
Erişilebilirlik ve Reduce Transparency
Liquid Glass'ın speküler vurguları ve gerçek zamanlı ışık kırılımı, Ayarlar > Erişilebilirlik > Ekran ve Metin Boyutu altındaki Şeffaflığı Azalt (Reduce Transparency) tercihiyle etkileşime giriyor. Sistem kontrolleri bu tercihi otomatik onurlandırıyor, ama glassEffect ile elle çizdiğiniz custom yüzeylerde bu davranışı siz test etmelisiniz — simülatörde Reduce Transparency açıkken UI'ınızın hâlâ okunabilir kaldığını doğrulamadan bir glass yüzeyi production'a almayın. Aynı şekilde Increase Contrast açıkken .tint() ile verilen renklerin metin/ikon kontrastını WCAG AA eşiğinin altına düşürmediğinden emin olun.
Sonuç
Liquid Glass, opsiyonel bir görsel yenileme değil — Xcode 26 SDK ile derleyen her SwiftUI uygulaması için varsayılan davranış. Gerçek iş, sistemin otomatik verdiği kazanımları bozmadan, gerçekten custom olan yüzeyleri glassEffect, GlassEffectContainer ve glassEffectID üçlüsüyle yeniden ifade etmek. tabBarMinimizeBehavior ve role: .search gibi yapısal API'lar navigasyon katmanını neredeyse ücretsiz modernize ediyor; UIDesignRequiresCompatibility ise yalnızca geçiş süresi kazandıran bir köprü, kalıcı mimari değil.
Production migrasyonuna başlamadan önce: eski materyal background'larınızı envanterleyin, glass container sınırlarını bilinçli çizin ve liste/koleksiyon hücrelerinde glass kullanmaktan kaçının. Bu üç kural, Liquid Glass'ı performans regresyonu olmadan benimsemenin en kısa yolu.
*Kaynaklar: Apple Developer Documentation (glassEffect(_:in:)), GlassEffectContainer, Applying Liquid Glass to custom views) ve WWDC25 Session 323 "Build a SwiftUI app with the new design".*

