Úvod do Liquid Glass
Na WWDC 2025 Apple ukázal něco, co se dá bez přehánění nazvat nejodvážnější designovou změnou od dob iOS 7 — Liquid Glass. Tento zcela nový designový meta-materiál zásadně mění způsob, jakým vypadají a fungují rozhraní napříč všemi Apple platformami. A spolu s ním přišlo i přečíslování — iOS přeskočil rovnou na verzi iOS 26, čímž se konečně sjednotil s interním číslováním, které Apple používal už léta.
Liquid Glass ale není jen další variace rozmazání pozadí nebo průhlednosti. Tohle je úplně jiná liga.
Jedná se o dynamický materiál, který využívá princip zvaný lensing — tedy ohýbání a koncentrování světla. Místo jednoduchého rozostření obsahu na pozadí Liquid Glass obsah láme a přesvětluje, podobně jako skutečné sklo nebo vodní kapka. Výsledek? Efekt, který působí hmatatelně, živě a fyzicky přítomně. Popravdě, když jsem ho poprvé viděl v akci, chvíli mi trvalo, než jsem si uvědomil, že se dívám na software, ne na skutečný materiál.
Tento materiál navíc reaguje na okolní prostředí v reálném čase. Nakloníte zařízení — světelné odlesky se posunou po povrchu skleněných prvků. Mění se obsah pod nimi? Lom světla se dynamicky přepočítává. A při klepnutí materiál reaguje jemnou elastickou deformací, jako byste se dotýkali fyzického skla.
Liquid Glass najdete na všech platformách — iOS, iPadOS, macOS Tahoe, watchOS, tvOS i visionOS. Pro nás vývojáře, kteří stavíme ve SwiftUI, to znamená skvělou zprávu: velká část změn se aplikuje automaticky, bez jediného řádku nového kódu. V tomto průvodci si projdeme všechno, co potřebujete vědět — od automatických změn přes nová API až po pravidla použití a pokročilé techniky.
Automatické změny bez kódu
Jedním z největších přínosů Liquid Glass je to, že spousta systémových komponent získá nový vzhled automaticky, jakmile svou aplikaci překompilujete v Xcode 26. Nemusíte měnit ani řádek. Pokud jste aplikaci stavěli s použitím standardních SwiftUI API, systém se postará o všechno sám.
Tady je seznam komponent, které se automaticky aktualizují na Liquid Glass design:
- NavigationBar — navigační panel získá plně skleněný vzhled s lomem světla
- TabBar — přemění se na plovoucí kapslový prvek s Liquid Glass efektem
- Toolbar — položky panelu nástrojů se vykreslí s efektem skla
- Sheets — modální listy získají skleněné pozadí
- Popovers — vyskakovací okna budou využívat lom světla
- Menus — kontextová menu ve stylu Liquid Glass
- Alerts — upozornění a dialogy přejdou na skleněný materiál
- Search bars — vyhledávací panely získají skleněný efekt
- Toggles, Sliders, Pickers — všechny se vizuálně aktualizují
Takže typická SwiftUI aplikace může vypadat moderně a v souladu s iOS 26 prostě jen překompilováním. Kdo používá standardní API, automaticky těží z vylepšení platformy — a tohle je toho krásný důkaz.
// Tento kód nevyžaduje žádnou změnu pro iOS 26.
// NavigationBar, TabBar i Toolbar automaticky získají Liquid Glass.
struct ContentView: View {
var body: some View {
TabView {
Tab("Domů", systemImage: "house") {
NavigationStack {
List {
ForEach(0..<20) { index in
Text("Položka \(index)")
}
}
.navigationTitle("Moje aplikace")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Přidat", systemImage: "plus") {
// akce
}
}
}
}
}
Tab("Nastavení", systemImage: "gear") {
Text("Nastavení")
}
}
}
}
Výše uvedený kód bude v Xcode 26 automaticky využívat Liquid Glass pro navigační panel, panel záložek i panel nástrojů. Žádné úpravy nejsou potřeba.
Samozřejmě existují situace, kdy potřebujete Liquid Glass aplikovat na vlastní komponenty — plovoucí tlačítka, vlastní panely nebo překryvné prvky. K tomu slouží nová API, která si probereme dál.
Základní API a modifikátory
Jádrem celého systému Liquid Glass ve SwiftUI je modifikátor .glassEffect(). Umožňuje aplikovat skleněný efekt na libovolný pohled a nabízí několik variant a parametrů pro jemné nastavení.
Výchozí použití
Nejjednodušší způsob, jak Liquid Glass aplikovat na vlastní pohled, je zavolat modifikátor bez parametrů. Ve výchozím stavu se použije varianta regular.
// Základní skleněný efekt (výchozí varianta regular)
Text("Ahoj, Liquid Glass!")
.padding()
.glassEffect()
Explicitní varianta Regular
Varianta .regular je standardní volba pro většinu scénářů. Vytváří poloprůhledný skleněný povrch, který mírně ztmavuje obsah pod sebou a přidává ten charakteristický lom světla.
// Explicitní regular varianta
Text("Standardní sklo")
.padding()
.glassEffect(.regular)
Varianta Clear
Varianta .clear vytváří průhlednější sklo s minimálním ztmavením pozadí. Je určena výhradně pro situace, kdy pozadí obsahuje bohatý vizuální obsah (fotky, videa, mapy) a vy ho nechcete příliš zastínit. O pravidlech jejího použití si řekneme víc v samostatné sekci.
// Clear varianta pro mediálně bohatá pozadí
Text("Průhledné sklo")
.padding()
.glassEffect(.clear)
Specifikace tvaru
Parametr in: vám umožňuje definovat tvar skleněného efektu. Můžete použít libovolný tvar ze SwiftUI — .capsule, .circle nebo .rect(cornerRadius:).
// Kapslový tvar
Text("Kapslové sklo")
.padding(.horizontal, 20)
.padding(.vertical, 10)
.glassEffect(.regular, in: .capsule)
// Zaoblený obdélník
Text("Zaoblené sklo")
.padding()
.glassEffect(.regular, in: .rect(cornerRadius: 16))
// Kruhový tvar
Image(systemName: "plus")
.font(.title2)
.frame(width: 56, height: 56)
.glassEffect(.regular, in: .circle)
Interaktivní efekt
Na iOS můžete přidat modifikátor .interactive(), který zapne elastickou odezvu při dotyku. Uživatel klepne, sklo se jemně stlačí a při uvolnění se s pružným efektem vrátí zpět. Zní to jako maličkost, ale tenhle vizuální feedback opravdu výrazně zlepšuje pocit z interakce.
// Interaktivní skleněný efekt s dotykovou odezvou (pouze iOS)
Button("Klepněte na mě") {
// akce
}
.padding()
.glassEffect(.regular.interactive())
Tónování (Tinting)
Skleněný efekt můžete obarvit pomocí .tint(). Tónování dodá sklu jemný barevný nádech — hodí se pro zvýraznění primárních akcí nebo odlišení skupin prvků.
// Modré tónování
Button("Primární akce") {
// akce
}
.padding()
.glassEffect(.regular.tint(.blue))
// Červené tónování s průhledností
Button("Smazat") {
// akce
}
.padding()
.glassEffect(.regular.tint(.red.opacity(0.8)))
// Kombinace interaktivity a tónování
Button("Uložit") {
// akce
}
.padding()
.glassEffect(
.regular
.interactive()
.tint(.green),
in: .capsule
)
GlassEffectContainer
Když máte víc skleněných prvků vedle sebe, musíte je seskupit pomocí GlassEffectContainer. Proč? Kontejner zajišťuje hned několik důležitých věcí:
- Sdílené vzorkování pozadí — všechny skleněné prvky uvnitř kontejneru sdílejí jednu referenci pozadí, což zabraňuje vizuálním artefaktům
- Jediný vykreslovací průchod — systém vykreslí všechny efekty najednou, což je výrazně efektivnější
- Morphing animace — kontejner umožňuje plynulé přechodové animace mezi prvky
- Automatické prolínání — okraje sousedních skleněných prvků se automaticky prolnou místo tvrdých hranic
// Základní použití GlassEffectContainer
GlassEffectContainer(spacing: 30) {
HStack(spacing: 20) {
Button("A") {
// akce
}
.glassEffect()
Button("B") {
// akce
}
.glassEffect()
Button("C") {
// akce
}
.glassEffect()
}
}
Bez GlassEffectContainer by každý prvek vzorkoval pozadí nezávisle, což by vedlo k nekonzistentnímu vzhledu a zbytečné zátěži. Kontejner je zvlášť důležitý pro panely nástrojů, skupiny tlačítek a jakékoliv situace, kde se více skleněných prvků nachází blízko sebe.
// Praktický příklad: Plovoucí panel nástrojů
struct FloatingToolbar: View {
var body: some View {
GlassEffectContainer(spacing: 16) {
HStack(spacing: 12) {
Button {
// akce tučné písmo
} label: {
Image(systemName: "bold")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
Button {
// akce kurzíva
} label: {
Image(systemName: "italic")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
Button {
// akce podtržení
} label: {
Image(systemName: "underline")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
Divider()
.frame(height: 24)
Button {
// akce barva textu
} label: {
Image(systemName: "paintbrush")
.frame(width: 44, height: 44)
}
.glassEffect(
.regular.tint(.blue),
in: .circle
)
}
.padding(.horizontal, 16)
.padding(.vertical, 8)
}
}
}
Morphing animace s glassEffectID
Tak, a teď přichází ta nejzábavnější část. Jednou z nejefektnějších funkcí Liquid Glass jsou morphing animace — plynulé přechody, při kterých se jeden skleněný prvek přetváří v jiný. Upřímně, když tohle funguje správně, vypadá to naprosto fantasticky.
Pro aktivaci morphing animace potřebujete splnit tři podmínky:
- Sdílený GlassEffectContainer — oba prvky musí být uvnitř stejného kontejneru
- Unikátní glassEffectID se sdíleným Namespace — každý prvek musí mít jedinečný identifikátor v rámci sdíleného jmenného prostoru
- Animace při změně stavu — změna stavu musí být zabalena v animačním bloku
struct MorphingExample: View {
@Namespace private var namespace
@State private var isExpanded = false
var body: some View {
GlassEffectContainer {
VStack {
if isExpanded {
// Rozšířený stav: horizontální panel s více tlačítky
HStack(spacing: 16) {
Button {
// fotoaparát
} label: {
Image(systemName: "camera")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
.glassEffectID("action1", in: namespace)
Button {
// fotogalerie
} label: {
Image(systemName: "photo")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
.glassEffectID("action2", in: namespace)
Button {
// sbalení
withAnimation(.spring(duration: 0.4)) {
isExpanded = false
}
} label: {
Image(systemName: "xmark")
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
.glassEffectID("toggle", in: namespace)
}
} else {
// Sbalený stav: jedno plovoucí tlačítko
Button {
withAnimation(.spring(duration: 0.4)) {
isExpanded = true
}
} label: {
Image(systemName: "plus")
.font(.title2)
.fontWeight(.semibold)
.frame(width: 56, height: 56)
}
.glassEffect(
.regular.interactive().tint(.blue),
in: .circle
)
.glassEffectID("toggle", in: namespace)
}
}
}
}
}
Všimněte si, jak sbalené tlačítko a zavírací tlačítko sdílejí stejné glassEffectID("toggle", in: namespace). Při změně stavu systém automaticky vytvoří plynulou morphing animaci — sbalené kruhové tlačítko se doslova přelije do rozšířeného panelu s více tlačítky. Efekt je vizuálně opravdu působivý.
Důležitý detail: morphing animace funguje pouze tehdy, když se identifikátor přesouvá mezi dvěma větvemi podmínky (if/else). Systém rozpozná, že prvek se stejným ID zmizí z jednoho místa a objeví se na jiném, a vytvoří plynulý přechod.
Styly tlačítek
SwiftUI v iOS 26 přidává dva nové styly tlačítek navržené speciálně pro Liquid Glass. Poskytují jednoduchý způsob, jak tlačítkům dát skleněný vzhled bez ruční konfigurace .glassEffect().
Styl .glass
Styl .glass vytváří poloprůhledné skleněné tlačítko ideální pro sekundární akce. Tlačítko je vizuálně přítomné, ale ne dominantní — splyne s okolním rozhraním.
// Poloprůhledné skleněné tlačítko pro sekundární akce
Button("Zrušit") {
// akce zrušení
}
.buttonStyle(.glass)
Styl .glassProminent
Styl .glassProminent vytváří neprůhledné, výraznější tlačítko určené pro primární akce. Je vizuálně dominantnější a jasně signalizuje hlavní akci.
// Výrazné skleněné tlačítko pro primární akce
Button("Potvrdit") {
// akce potvrzení
}
.buttonStyle(.glassProminent)
Praktická kombinace
// Kombinace obou stylů v dialogu
struct ConfirmationPanel: View {
var body: some View {
VStack(spacing: 16) {
Text("Opravdu chcete smazat tento soubor?")
.font(.headline)
Text("Tuto akci nelze vrátit zpět.")
.font(.subheadline)
.foregroundStyle(.secondary)
HStack(spacing: 12) {
Button("Zrušit") {
// zrušení akce
}
.buttonStyle(.glass)
Button("Smazat") {
// akce smazání
}
.buttonStyle(.glassProminent)
.tint(.red)
}
}
.padding(24)
}
}
Při rozhodování mezi styly platí jednoduché pravidlo: .glassProminent pro hlavní akci na obrazovce, .glass pro všechno ostatní. Na jedné obrazovce by měla být maximálně jedna prominentní akce, aby hierarchie zůstala čitelná.
Pravidla a best practices
Správné použití Liquid Glass je zásadní pro soudržné a uživatelsky přívětivé rozhraní. Apple stanovil jasná pravidla a porušení některých z nich může vést k vizuálním problémům, snížené čitelnosti a celkově špatnému zážitku. Pojďme si je projít.
Zlaté pravidlo
Liquid Glass patří výhradně do navigační vrstvy, která se vznáší nad obsahem. Tohle je nejdůležitější pravidlo celého systému. Liquid Glass slouží jako vizuální odlišení prvků pro navigaci a ovládání — ne jako dekorace obsahu samotného.
Kde Liquid Glass použít
- Panely nástrojů (Toolbars) — ideální kandidát, vznášejí se nad obsahem
- Panely záložek (TabBars) — plovoucí skleněný efekt přímo vyžadují
- Postranní panely (Sidebars) — na macOS a iPadOS pro navigační hierarchii
- Plovoucí akční tlačítka (FABs) — tlačítka plovoucí nad obsahem
- Modální listy a vyskakovací okna — překryvné prvky s obsahem
Kde Liquid Glass nikdy nepoužívat
- Vrstvy obsahu — texty, obrázky, seznamy nemají mít skleněný efekt
- Pozadí na celou obrazovku — sklo potřebuje obsah pod sebou; na celé obrazovce prostě nedává smysl
- Rolující obsah — buňky v seznamu, karty ve skrolovacím zobrazení a podobné prvky nemají být skleněné
Nikdy neskládejte sklo na sklo
Tohle je jedno z nejkritičtějších pravidel. Nikdy neaplikujte Liquid Glass na prvek, který už leží na jiném Liquid Glass prvku. Vrstvení skla na sklo vytváří vizuální chaos — systém nedokáže správně vypočítat lom světla přes dvě skleněné vrstvy a výsledek vypadá jednoduše rozbitě.
// ŠPATNĚ: Sklo na skle
VStack {
Text("Vnořený obsah")
.padding()
.glassEffect() // Toto je ŠPATNĚ — sklo na skle!
}
.padding()
.glassEffect() // Vnější sklo
// SPRÁVNĚ: Pouze jedna vrstva skla
VStack {
Text("Vnořený obsah")
.padding()
// Žádný skleněný efekt na vnitřním obsahu
}
.padding()
.glassEffect() // Pouze vnější sklo
Nemíchejte varianty Regular a Clear
Na jedné obrazovce byste neměli kombinovat varianty .regular a .clear. Každá má odlišný stupeň ztmavení pozadí a jejich mix vytváří vizuální nekonzistenci. Rozhodněte se pro jednu a tu používejte konzistentně.
Tónování jen pro primární prvky
Barevné tónování (.tint()) by mělo být vyhrazeno pro prvky, které si zaslouží zvláštní pozornost — typicky primární akční tlačítka. Pokud obarvíte úplně všechno, nic nevynikne a celá hierarchie se ztratí.
// SPRÁVNĚ: Tónování pouze pro primární akci
GlassEffectContainer {
HStack(spacing: 12) {
Button("Sdílet") {
// akce sdílení
}
.glassEffect(.regular, in: .capsule)
Button("Uložit") {
// akce uložení
}
.glassEffect(.regular, in: .capsule)
// Pouze primární akce má tónování
Button("Odeslat") {
// akce odeslání
}
.glassEffect(
.regular.tint(.blue),
in: .capsule
)
}
}
Clear varianta — kdy a jak ji použít
Varianta .clear je speciální případ, který vyžaduje zvláštní pozornost. Na rozdíl od .regular, která mírně ztmavuje pozadí pro zajištění čitelnosti, .clear je téměř průhledná a do obsahu pod sebou minimálně zasahuje.
Použijte ji pouze tehdy, když jsou splněny všechny tři následující podmínky:
- Pozadí je mediálně bohaté — pod sklem se nachází fotka, video, mapa nebo jiný vizuálně intenzivní obsah
- Ztmavení by vadilo — výrazně by zhoršilo zážitek z prohlížení obsahu
- Obsah nad sklem je dostatečně výrazný — text a ikony jsou dost tučné, velké nebo kontrastní, aby zůstaly čitelné i bez ztmavení
// Příklad použití Clear varianty nad fotografií
struct MediaOverlay: View {
var body: some View {
ZStack {
// Mediálně bohaté pozadí
Image("landscape")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
// Plovoucí ovládací prvky s Clear variantou
VStack {
Spacer()
HStack(spacing: 16) {
Button {
// sdílení
} label: {
Image(systemName: "square.and.arrow.up")
.font(.title2)
.fontWeight(.bold)
.foregroundStyle(.white)
.frame(width: 48, height: 48)
}
.glassEffect(.clear, in: .circle)
Spacer()
Button {
// oblíbené
} label: {
Image(systemName: "heart.fill")
.font(.title2)
.fontWeight(.bold)
.foregroundStyle(.white)
.frame(width: 48, height: 48)
}
.glassEffect(.clear, in: .circle)
}
.padding(.horizontal, 24)
.padding(.bottom, 16)
}
}
}
}
Pokud si nejste jistí, kterou variantu zvolit, sáhněte po .regular. Je to bezpečnější volba. Variantu .clear používejte jen tam, kde je to opravdu opodstatněné.
Přístupnost
Apple věnoval hodně pozornosti tomu, aby Liquid Glass bylo plně přístupné. A dobrá zpráva je, že pokud používáte standardní API (.glassEffect()), veškerá přístupnostní adaptace se děje automaticky. Nemusíte psát ani řádek navíc.
Snížit průhlednost (Reduce Transparency)
Když uživatel zapne toto nastavení, Liquid Glass automaticky zvýší neprůhlednost. Místo průhledného skla se zobrazí matnější povrch, který je méně průhledný, ale stále zachovává jemný efekt. Výsledek — lepší čitelnost.
Zvýšit kontrast (Increase Contrast)
Při zapnutém zvýšeném kontrastu se Liquid Glass přemění na plně neprůhledný povrch — černý v tmavém režimu, bílý ve světlém — s výraznými hranicemi. Průhledné efekty se prostě vypnou.
Snížit pohyb (Reduce Motion)
Systém vypne elastické animace, morphing přechody a dynamické odlesky. Prvky stále vypadají jako sklo, ale bez animací, které by mohly některým uživatelům vadit.
// Nemusíte psát žádný speciální kód pro přístupnost.
// Systém se postará o vše automaticky.
// Tento kód bude automaticky přístupný:
Button("Akce") {
// akce
}
.padding()
.glassEffect(.regular.interactive(), in: .capsule)
// Reduce Transparency → matnější sklo
// Increase Contrast → neprůhledné s okraji
// Reduce Motion → bez elastických animací
Jediná situace, kdy se musíte o přístupnost starat ručně, je pokud vytváříte vlastní implementaci skleněného efektu místo .glassEffect(). V tom případě sledujte příslušná nastavení prostředí:
// Sledování nastavení přístupnosti pro vlastní implementace
struct CustomGlassView: View {
@Environment(\.accessibilityReduceTransparency)
var reduceTransparency
@Environment(\.accessibilityReduceMotion)
var reduceMotion
@Environment(\.colorSchemeContrast)
var contrast
var body: some View {
RoundedRectangle(cornerRadius: 16)
.fill(reduceTransparency
? .regularMaterial
: .ultraThinMaterial
)
.overlay {
if contrast == .increased {
RoundedRectangle(cornerRadius: 16)
.stroke(.primary, lineWidth: 2)
}
}
.animation(
reduceMotion ? .none : .spring(),
value: reduceTransparency
)
}
}
Praktický příklad: Vlastní plovoucí panel
Pojďme teď spojit všechno dohromady. Vytvoříme plovoucí akční panel, který využívá skleněný efekt, kontejner, tónování i morphing animace. Tohle je ten typ kódu, který si pak můžete vzít a upravit pro své vlastní projekty.
struct FloatingActionPanel: View {
@Namespace private var panelNamespace
@State private var panelState: PanelState = .collapsed
@State private var selectedColor: Color = .blue
enum PanelState {
case collapsed
case expanded
case colorPicker
}
var body: some View {
ZStack {
// Hlavní obsah aplikace
ScrollView {
LazyVStack(spacing: 12) {
ForEach(0..<30) { index in
HStack {
RoundedRectangle(cornerRadius: 8)
.fill(Color.gray.opacity(0.2))
.frame(width: 60, height: 60)
VStack(alignment: .leading, spacing: 4) {
Text("Položka \(index + 1)")
.font(.headline)
Text("Popis položky pro demonstraci skrolování")
.font(.subheadline)
.foregroundStyle(.secondary)
}
Spacer()
}
.padding(.horizontal)
}
}
.padding(.vertical)
}
// Plovoucí panel
VStack {
Spacer()
HStack {
Spacer()
floatingPanel
.padding(.trailing, 24)
.padding(.bottom, 16)
}
}
}
}
@ViewBuilder
private var floatingPanel: some View {
GlassEffectContainer {
switch panelState {
case .collapsed:
// Sbalený stav: jedno tlačítko
Button {
withAnimation(.spring(duration: 0.5, bounce: 0.3)) {
panelState = .expanded
}
} label: {
Image(systemName: "plus")
.font(.title2)
.fontWeight(.bold)
.foregroundStyle(.white)
.frame(width: 60, height: 60)
}
.glassEffect(
.regular
.interactive()
.tint(selectedColor),
in: .circle
)
.glassEffectID("mainButton", in: panelNamespace)
case .expanded:
// Rozšířený stav: panel s akcemi
VStack(spacing: 12) {
Button {
withAnimation(.spring(duration: 0.4)) {
panelState = .colorPicker
}
} label: {
Label("Barva", systemImage: "paintpalette")
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
}
.glassEffect(.regular, in: .capsule)
.glassEffectID("colorAction", in: panelNamespace)
Button {
// akce sdílení
} label: {
Label("Sdílet", systemImage: "square.and.arrow.up")
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
}
.glassEffect(.regular, in: .capsule)
Button {
// akce uložení
} label: {
Label("Uložit", systemImage: "square.and.arrow.down")
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
}
.glassEffect(
.regular.tint(.green),
in: .capsule
)
Divider()
Button {
withAnimation(.spring(duration: 0.4)) {
panelState = .collapsed
}
} label: {
Image(systemName: "xmark")
.font(.title3)
.fontWeight(.semibold)
.frame(width: 44, height: 44)
}
.glassEffect(.regular, in: .circle)
.glassEffectID("mainButton", in: panelNamespace)
}
.frame(width: 200)
.padding(16)
case .colorPicker:
// Výběr barvy
VStack(spacing: 12) {
Text("Vyberte barvu")
.font(.headline)
LazyVGrid(
columns: Array(repeating: .init(.flexible()), count: 4),
spacing: 8
) {
ForEach(
[Color.blue, .red, .green, .orange,
.purple, .pink, .teal, .indigo],
id: \.self
) { color in
Button {
selectedColor = color
withAnimation(.spring(duration: 0.4)) {
panelState = .expanded
}
} label: {
Circle()
.fill(color)
.frame(width: 36, height: 36)
}
.glassEffect(
.regular.tint(color),
in: .circle
)
}
}
Button {
withAnimation(.spring(duration: 0.4)) {
panelState = .expanded
}
} label: {
Text("Zpět")
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
}
.glassEffect(.regular, in: .capsule)
.glassEffectID("colorAction", in: panelNamespace)
}
.frame(width: 220)
.padding(16)
}
}
}
}
Tenhle příklad ukazuje několik klíčových konceptů najednou:
- GlassEffectContainer obaluje celý plovoucí panel a zajišťuje sdílené vzorkování
- Morphing animace — sledujte, jak se identifikátor
"mainButton"přesouvá mezi sbaleným a rozšířeným stavem - Tónování je použito selektivně — pouze pro primární tlačítko a uložení
- Interaktivní efekt na hlavním plovoucím tlačítku ve sbaleném stavu
- Různé tvary — kruhy pro ikony, kapsle pro textová tlačítka
macOS Tahoe a AppKit
Liquid Glass samozřejmě není jen pro SwiftUI a iOS. Na macOS Tahoe ho můžete využít i v AppKit aplikacích. I když je SwiftUI preferovaná cesta, Apple poskytl podporu i pro tradiční AppKit.
NSButton s Glass bezel stylem
V AppKit lze tlačítkům přiřadit nový styl fazety .glass:
// AppKit: NSButton se skleněným stylem
let button = NSButton()
button.title = "Akce"
button.bezelStyle = .glass
Automatické seskupování v panelech nástrojů
Na macOS Tahoe se položky v NSToolbar automaticky seskupí do skleněných skupin. Systém sám rozpozná, které položky spolu souvisejí, a vykreslí je v rámci jednoho kontejneru. Tohle je čistě automatické — žádné změny v kódu nepotřebujete.
Ambientní odraz v postranním panelu
Postranní panely na macOS Tahoe získávají efekt ambientního odrazu. Skleněný povrch jemně odráží barvy obsahu v hlavní oblasti aplikace, čímž vytváří vizuální provázanost mezi navigací a obsahem. Aktivuje se automaticky pro standardní NSSplitViewController konfigurace. Je to drobný detail, ale dělá hodně pro celkový dojem z aplikace.
// SwiftUI na macOS Tahoe: Automatický Liquid Glass
struct MacApp: View {
@State private var selectedItem: String?
var body: some View {
NavigationSplitView {
// Postranní panel s ambientním odrazem
List(selection: $selectedItem) {
Section("Kategorie") {
Label("Dokumenty", systemImage: "doc")
.tag("dokumenty")
Label("Fotografie", systemImage: "photo")
.tag("fotografie")
Label("Videa", systemImage: "film")
.tag("videa")
}
}
.navigationTitle("Knihovna")
} detail: {
if let selected = selectedItem {
Text("Detail: \(selected)")
} else {
ContentUnavailableView(
"Vyberte položku",
systemImage: "sidebar.left",
description: Text("Zvolte kategorii v postranním panelu.")
)
}
}
}
}
Migrace existujících aplikací
Přechod existující aplikace na Liquid Glass je ve většině případů celkem plynulý, ale vyžaduje pozornost k několika klíčovým oblastem.
Zkontrolujte vlastní materiály
Pokud jste používali vlastní vizuální materiály jako .ultraThinMaterial nebo .regularMaterial, zkontrolujte, jestli se na místech s Liquid Glass stále vizuálně hodí. Někdy bude lepší je nahradit .glassEffect().
// PŘED: Vlastní materiálová vrstva
Text("Panel nástrojů")
.padding()
.background(.ultraThinMaterial)
.clipShape(.capsule)
// PO: Liquid Glass efekt
Text("Panel nástrojů")
.padding()
.glassEffect(.regular, in: .capsule)
Odstraňte nadbytečné rozmazání
Spousta aplikací používala vlastní blur efekty pomocí .blur() k napodobení efektu skla. Tyto vlastní implementace by měly být nahrazeny nativním .glassEffect(), který je nejen vizuálně konzistentní, ale taky výkonnější — systém optimalizuje vykreslování na úrovni GPU.
// PŘED: Vlastní blur efekt
VStack {
// obsah
}
.background {
RoundedRectangle(cornerRadius: 16)
.fill(.white.opacity(0.2))
.blur(radius: 10)
}
// PO: Nativní Liquid Glass
VStack {
// obsah
}
.glassEffect(.regular, in: .rect(cornerRadius: 16))
Testujte s nastavením přístupnosti
Po migraci je zásadní otestovat aplikaci se zapnutým Snížit průhlednost, Zvýšit kontrast a Snížit pohyb. Se standardním API by měl systém zvládnout všechno sám, ale u vlastních implementací musíte ověřit, že správně reagují.
Kontrola vizuální hierarchie
Po migraci zkontrolujte, zda je hierarchie prvků stále jasná. Skleněné prvky by měly být zřetelně odlišitelné od obsahu. Pokud se některé prvky ztrácejí, zvažte úpravu rozmístění nebo tónování.
Postupná migrace
Nemusíte migrovat všechno najednou. Doporučený postup je:
- Překompilujte v Xcode 26 — systémové komponenty se aktualizují automaticky
- Zkontrolujte vizuální konzistenci — ujistěte se, že automaticky aktualizované prvky vypadají správně
- Migrujte vlastní plovoucí prvky — nahraďte vlastní materiály a blur efekty modifikátorem
.glassEffect() - Přidejte GlassEffectContainer — seskupte související skleněné prvky
- Implementujte morphing animace — kde to dává smysl, přidejte
glassEffectID - Otestujte přístupnost — ověřte všechna nastavení
// Příklad postupné migrace existující aplikace
struct MigratedApp: View {
@State private var selectedTab = 0
var body: some View {
// Krok 1: TabView se automaticky aktualizuje
TabView(selection: $selectedTab) {
// Krok 2: NavigationStack se automaticky aktualizuje
NavigationStack {
ZStack {
// Obsah zůstává beze změn
ScrollView {
VStack(spacing: 16) {
ForEach(0..<20) { index in
ContentCard(index: index)
}
}
.padding()
}
// Krok 3: Vlastní plovoucí prvek
// migrovaný na Liquid Glass
VStack {
Spacer()
HStack {
Spacer()
// Krok 4 & 5: Container a morphing
GlassEffectContainer {
Button {
// nová položka
} label: {
Image(systemName: "plus")
.font(.title2)
.fontWeight(.bold)
.frame(width: 56, height: 56)
}
.glassEffect(
.regular.interactive().tint(.blue),
in: .circle
)
}
.padding(24)
}
}
}
.navigationTitle("Domů")
}
.tabItem {
Label("Domů", systemImage: "house")
}
.tag(0)
NavigationStack {
Text("Nastavení")
.navigationTitle("Nastavení")
}
.tabItem {
Label("Nastavení", systemImage: "gear")
}
.tag(1)
}
}
}
struct ContentCard: View {
let index: Int
var body: some View {
// Obsah aplikace NEMÁ používat Liquid Glass
VStack(alignment: .leading, spacing: 8) {
Text("Karta \(index + 1)")
.font(.headline)
Text("Toto je obsah karty. Obsah nemá používat skleněný efekt.")
.font(.body)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(Color(.secondarySystemBackground))
.clipShape(.rect(cornerRadius: 12))
}
}
Závěr
Liquid Glass je bezpochyby největší vizuální změna od přechodu na plochý design v iOS 7. A i když se to může zdát jako hodně nového, pro vývojáře, kteří používají standardní SwiftUI API, je přechod překvapivě hladký.
Pojďme si shrnout to nejdůležitější:
- Automatická adopce — překompilujte v Xcode 26 a systémové komponenty získají nový vzhled bez jakýchkoliv změn
- .glassEffect() — hlavní API pro vlastní prvky s variantami
.regulara.clear, podporou tvarů, interaktivity a tónování - GlassEffectContainer — nezbytný pro seskupení více skleněných prvků a morphing animace
- Morphing animace — pomocí
glassEffectIDa sdíleného jmenného prostoru vytváříte plynulé přechody - Zlaté pravidlo — sklo patří jen do navigační vrstvy; nikdy na obsah, nikdy sklo na sklo
- Přístupnost — systém automaticky přizpůsobuje efekty, pokud používáte standardní API
- Multiplatformní — funguje na iOS, iPadOS, macOS Tahoe, watchOS, tvOS i visionOS
Liquid Glass není jen kosmetická záležitost — je to promyšlený designový systém, který při správném použití dokáže výrazně zlepšit uživatelský zážitek. Klíč k úspěchu? Disciplína. Používejte sklo tam, kde patří, respektujte pravidla hierarchie a vždycky testujte s nastavením přístupnosti.
S příchodem iOS 26 začíná nová éra designu aplikací pro Apple platformy. Je čas se na ni připravit.