Liquid Glass in SwiftUI voor iOS 26: De Complete Gids

Leer hoe je Liquid Glass implementeert in je SwiftUI-apps voor iOS 26. Van de .glassEffect()-modifier en GlassEffectContainer tot morph-transities, toolbars, tab bars, sheets en best practices — inclusief werkende codevoorbeelden.

Inleiding: Een Nieuwe Designtaal voor Apple

Als je de laatste jaren iOS-apps hebt gebouwd, dan weet je dat het visuele ontwerp van het platform best stabiel was. Sinds iOS 7 in 2013 flat design introduceerde, zijn de ontwerpprincipes eigenlijk nooit écht drastisch veranderd. Ja, er kwamen nieuwe features bij — Dark Mode, widgets, Dynamic Island — maar de kern? Die bleef gewoon herkenbaar.

Tot iOS 26.

Op WWDC 2025 onthulde Apple Liquid Glass: de meest ingrijpende visuele vernieuwing in meer dan tien jaar. En eerlijk gezegd, als SwiftUI-ontwikkelaar krijg je er verrassend veel gratis bij. Maar om het écht goed in te zetten — en niet alleen de standaardinstellingen te gebruiken — moet je de nieuwe API's en ontwerpprincipes begrijpen.

In deze gids lopen we door alles wat je moet weten over Liquid Glass in SwiftUI. Van de basis van de .glassEffect()-modifier tot geavanceerde morph-transities met GlassEffectContainer, van toolbar-aanpassingen tot toegankelijkheid. Met praktische codevoorbeelden die je direct kunt gebruiken in je eigen projecten.

Wat Is Liquid Glass?

Liquid Glass is een nieuw adaptief materiaal dat Apple heeft ontwikkeld voor besturingselementen en navigatie. Het combineert de optische eigenschappen van glas — lichtbreking, reflectie, transparantie — met de vloeiendheid van vloeistof. Het resultaat is een lichtgewicht, dynamisch materiaal dat echt leeft op je scherm.

De belangrijkste visuele kenmerken:

  • Real-time lichtbreking (lensing): Het materiaal buigt het licht van de achterliggende content, waardoor een subtiel vergrotingseffect ontstaat.
  • Speculaire highlights: Lichtreflecties die dynamisch reageren op de beweging van het apparaat en de positie van de gebruiker.
  • Adaptieve schaduwen: Schaduwen die zich automatisch aanpassen aan de achtergrondcontent en lichtomstandigheden.
  • Interactief gedrag: Het materiaal reageert op aanrakingen met subtiele animaties.

Het kernprincipe achter Liquid Glass is gelaagdheid: content zit op de onderste laag, terwijl navigatie-elementen als glazen oppervlakken erboven zweven. Dit creëert een duidelijke visuele hiërarchie die de aandacht op de content richt.

Liquid Glass is beschikbaar op alle Apple-platforms: iOS 26, iPadOS 26, macOS Tahoe, watchOS 26, tvOS 26 en visionOS 26. Overigens is het geïnspireerd door de interface van de Vision Pro — Apple brengt hiermee een uniforme designtaal naar al hun apparaten.

Automatische Adoptie: Wat Je Gratis Krijgt

Goed nieuws. Als je je app opnieuw compileert met Xcode 26, krijg je automatisch het Liquid Glass-uiterlijk voor veel standaard UI-elementen. Letterlijk niets voor doen.

Deze elementen krijgen automatisch een Liquid Glass-behandeling:

  • NavigationBar — De navigatiebalk wordt transparant met een glazen achtergrond
  • TabBar — Tab-balken krijgen het nieuwe glazen uiterlijk en kunnen inkrimpen bij scrollen
  • Toolbars — Toolbar-items worden op een glazen oppervlak geplaatst
  • Sheets — Gedeeltelijke sheets zweven nu boven de interface met afgeronde hoeken
  • Popovers en Menu's — Krijgen automatisch het glazen materiaal
  • Alerts — Meldingen gebruiken het nieuwe materiaal
  • Zoekbalken — De zoekinterface past zich aan
  • Toggles, Sliders en Pickers — Transformeren naar Liquid Glass tijdens interactie

Dat gezegd hebbende: je wilt waarschijnlijk wél controleren hoe je voorgrond-elementen contrasteren met de dynamische achtergrond. Omdat Liquid Glass transparant is, kan de leesbaarheid van tekst en iconen veranderen afhankelijk van wat erachter zit. Dat is iets om in de gaten te houden.

De .glassEffect() Modifier: De Basis

De kern van het Liquid Glass-systeem in SwiftUI is de .glassEffect()-modifier. Hiermee pas je het glazen materiaal toe op elke SwiftUI-view.

De eenvoudigste vorm

In zijn meest basale vorm voeg je simpelweg .glassEffect() toe aan een view:

import SwiftUI

struct GlasKnopView: View {
    var body: some View {
        Button("Tik hier") {
            print("Knop ingedrukt!")
        }
        .padding(.horizontal, 24)
        .padding(.vertical, 12)
        .glassEffect()
    }
}

Standaard gebruikt .glassEffect() de .regular-stijl met een .capsule-vorm. De volledige signatuur ziet er zo uit:

.glassEffect(
    _ glass: Glass = .regular,
    in shape: some Shape = .capsule,
    isEnabled: Bool = true
) -> some View

Je kunt dus de stijl, vorm en of het effect actief is allemaal configureren. Lekker flexibel.

Glass-stijlen: Regular, Clear en Identity

Het Glass-type biedt drie statische varianten die bepalen hoe het glazen materiaal eruitziet.

.regular — De standaard

Glass.regular is de standaardvariant en biedt een gebalanceerde mix van transparantie, vervaging en lichtbreking. Dit is wat je in de meeste gevallen wilt gebruiken:

Text("Regulier glas")
    .padding()
    .glassEffect(.regular)

.clear — Hoge transparantie

Glass.clear biedt een hogere mate van transparantie met minimale vervaging. Handig voor elementen die minder visuele nadruk nodig hebben:

Text("Helder glas")
    .padding()
    .glassEffect(.clear)

.identity — Geen effect

Glass.identity schakelt het glaseffect effectief uit. Dit is vooral handig in combinatie met conditionele logica — denk bijvoorbeeld aan toegankelijkheid:

@Environment(\.accessibilityReduceTransparency) var verminderdTransparantie

var body: some View {
    Text("Adaptief glas")
        .padding()
        .glassEffect(verminderdTransparantie ? .identity : .regular)
}

Let op: Meng .regular en .clear niet binnen dezelfde groep besturingselementen. Dat creëert een verwarrende visuele hiërarchie. Kies één stijl per controlegroep.

Tinten en Interactiviteit

Glass-effecten kun je aanvullen met kleur en interactief gedrag. Dat maakt de gebruikerservaring een stuk rijker.

Kleurtinten toevoegen

Met de .tint()-methode op een Glass-instantie voeg je een subtiele kleurlaag toe aan het glaseffect:

// Blauwe tint voor een primaire actie
Button("Opslaan") { bewaarDocument() }
    .padding()
    .glassEffect(.regular.tint(.blue))

// Paarse tint met aangepaste dekking
Button("Delen") { deelDocument() }
    .padding()
    .glassEffect(.regular.tint(.purple.opacity(0.6)))

Een belangrijke richtlijn van Apple hier: gebruik tinten alleen om semantische betekenis over te brengen. Blauw voor een primaire actie, rood voor een destructieve — dat zijn goede toepassingen. Tinten puur voor de sier? Dat voegt visuele ruis toe en is af te raden.

Interactiviteit inschakelen

Met .interactive() reageert het glaseffect op aanrakingen met subtiele animaties:

Button("Interactieve knop") {
    voerActieUit()
}
.padding()
.glassEffect(.regular.interactive())

// Combineer tint en interactiviteit — de volgorde maakt niet uit
Button("Primaire actie") {
    voerPrimaireActieUit()
}
.padding()
.glassEffect(.regular.tint(.blue).interactive())

Schakel interactiviteit alleen in op aantikbare elementen. Op passieve content zoals labels voegt het onnodige renderingkosten toe zonder dat de gebruiker er iets aan heeft.

Aangepaste Vormen

De .glassEffect()-modifier accepteert elke SwiftUI Shape als parameter. Dat geeft je volledige controle over de visuele begrenzing van het glasoppervlak.

// Capsule — de standaard
Text("Capsule")
    .padding()
    .glassEffect(.regular, in: .capsule)

// Cirkel
Image(systemName: "star.fill")
    .font(.title)
    .frame(width: 60, height: 60)
    .glassEffect(.regular, in: .circle)

// Afgeronde rechthoek
VStack {
    Text("Kaartweergave")
    Text("Met glaseffect")
        .font(.caption)
}
.padding()
.glassEffect(.regular, in: RoundedRectangle(cornerRadius: 16))

// Container-concentrische hoeken
Text("Concentrisch")
    .padding()
    .glassEffect(.regular, in: .rect(cornerRadius: .containerConcentric))

Die .containerConcentric-optie is trouwens bijzonder handig: het past de hoekradius automatisch aan zodat deze visueel mooi samenvalt met de container eromheen. Perfect voor geneste elementen.

Eigen vormen definiëren

Je kunt ook volledig aangepaste vormen gebruiken. Alles dat voldoet aan het Shape-protocol werkt gewoon:

struct DiamantVorm: Shape {
    func path(in rect: CGRect) -> Path {
        var pad = Path()
        pad.move(to: CGPoint(x: rect.midX, y: rect.minY))
        pad.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
        pad.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
        pad.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
        pad.closeSubpath()
        return pad
    }
}

// Gebruik de aangepaste vorm
Image(systemName: "diamond.fill")
    .font(.largeTitle)
    .frame(width: 80, height: 80)
    .glassEffect(.regular, in: DiamantVorm())

GlassEffectContainer: Groeperen en Morphen

Oké, hier wordt het echt interessant. Een van de krachtigste features van het Liquid Glass-systeem is de GlassEffectContainer. Deze container combineert meerdere glasvormen tot één samenhangende glasvorm die kan morphen en blenden.

Basisgebruik

Wanneer je views met .glassEffect() in een GlassEffectContainer plaatst, gebeuren er automatisch een paar dingen:

  • Overlappende glasvormen worden visueel samengevoegd
  • Consistente vervagings- en lichteffecten worden toegepast
  • Vloeiende morph-transities worden mogelijk
  • De rendering-prestaties verbeteren
struct GlasToolbarView: View {
    var body: some View {
        ZStack {
            // Achtergrondafbeelding
            Image("landschap")
                .resizable()
                .ignoresSafeArea()

            // Glascontainer met knoppen
            GlassEffectContainer {
                HStack(spacing: 16) {
                    Button {
                        // Actie
                    } label: {
                        Image(systemName: "house.fill")
                    }
                    .glassEffect()

                    Button {
                        // Actie
                    } label: {
                        Image(systemName: "gear")
                    }
                    .glassEffect()

                    Button {
                        // Actie
                    } label: {
                        Image(systemName: "person.fill")
                    }
                    .glassEffect()
                }
                .padding()
            }
        }
    }
}

De spacing-parameter

De GlassEffectContainer accepteert een optionele spacing-parameter die bepaalt hoe dicht elementen bij elkaar moeten zijn voordat ze visueel samensmelten:

// Elementen binnen 40 punten smelten samen
GlassEffectContainer(spacing: 40.0) {
    HStack(spacing: 20) {
        ForEach(iconen, id: \.self) { icoon in
            Image(systemName: icoon)
                .font(.title2)
                .frame(width: 44, height: 44)
                .glassEffect()
        }
    }
}

Een hogere spacing-waarde betekent dat elementen eerder samensmelten. Speel hier gerust mee om het juiste visuele effect te vinden voor jouw situatie.

Morph-transities met glassEffectID

Het échte magie van GlassEffectContainer komt naar voren bij morph-transities. Met .glassEffectID() koppel je gerelateerde glaselementen aan elkaar, zodat ze vloeiend kunnen transformeren tussen staten.

Een uitklapbaar actiemenu bouwen

Dit is een populair UI-patroon dat je vast al kent: een floating action button die uitklapt naar meerdere opties. Met Liquid Glass ziet het er fantastisch uit:

struct UitklapbaarActieMenu: View {
    @State private var isUitgeklapt = false
    @Namespace private var namespace

    let acties: [(naam: String, icoon: String, kleur: Color)] = [
        ("Camera", "camera.fill", .blue),
        ("Foto", "photo.fill", .green),
        ("Document", "doc.fill", .orange)
    ]

    var body: some View {
        VStack {
            Spacer()

            GlassEffectContainer(spacing: 20) {
                VStack(spacing: 12) {
                    if isUitgeklapt {
                        ForEach(acties, id: \.naam) { actie in
                            Button {
                                // Voer actie uit
                            } label: {
                                Image(systemName: actie.icoon)
                                    .font(.title2)
                                    .frame(width: 50, height: 50)
                            }
                            .glassEffect(
                                .regular.tint(actie.kleur),
                                in: .circle
                            )
                            .glassEffectID(actie.naam, in: namespace)
                        }
                    }

                    Button {
                        withAnimation(.bouncy(duration: 0.4)) {
                            isUitgeklapt.toggle()
                        }
                    } label: {
                        Image(systemName: isUitgeklapt
                            ? "xmark" : "plus")
                            .font(.title)
                            .frame(width: 60, height: 60)
                    }
                    .glassEffect(.regular.interactive(), in: .circle)
                    .glassEffectID("hoofdknop", in: namespace)
                }
            }
            .padding(.bottom, 30)
        }
    }
}

De stappen voor een morph-transitie zijn eigenlijk best overzichtelijk:

  1. Plaats alle deelnemende views in dezelfde GlassEffectContainer
  2. Gebruik .glassEffectID() met een gemeenschappelijke @Namespace op elke view
  3. Toon views conditioneel met een animatie

Het resultaat? Een vloeiende, natuurlijke transitie waarbij de glasvormen in elkaar overlopen. Precies het soort polish dat een goede app onderscheidt van een geweldige.

Toolbars in het Liquid Glass-tijdperk

Toolbars hebben een flinke visuele update gekregen in iOS 26. Toolbar-items worden nu op een glazen oppervlak geplaatst dat boven je content zweeft en zich automatisch aanpast aan wat eronder zit.

De nieuwe ToolbarSpacer

Een van de handige nieuwe toevoegingen is ToolbarSpacer. Hiermee kun je toolbar-items groeperen en scheiden op een manier die voorheen nogal omslachtig was:

struct DocumentEditorView: View {
    var body: some View {
        NavigationStack {
            TextEditor(text: .constant("Documentinhoud..."))
                .toolbar {
                    ToolbarItemGroup(placement: .bottomBar) {
                        Button {
                            // Vet
                        } label: {
                            Image(systemName: "bold")
                        }

                        Button {
                            // Cursief
                        } label: {
                            Image(systemName: "italic")
                        }

                        // Vaste ruimte tussen groepen
                        ToolbarSpacer(.fixed, spacing: 20)

                        Button {
                            // Links uitlijnen
                        } label: {
                            Image(systemName: "text.alignleft")
                        }

                        Button {
                            // Centreren
                        } label: {
                            Image(systemName: "text.aligncenter")
                        }

                        // Flexibele ruimte duwt naar rechts
                        ToolbarSpacer(.flexible)

                        Button {
                            // Delen
                        } label: {
                            Image(systemName: "square.and.arrow.up")
                        }
                    }
                }
        }
    }
}

ToolbarSpacer(.fixed, spacing:) creëert een vaste ruimte tussen items, terwijl ToolbarSpacer(.flexible) zich uitbreidt om beschikbare ruimte op te vullen. Simpel, maar effectief voor het maken van visueel duidelijke groepen.

Toolbar-plaatsing en glasstijlen

In het Liquid Glass-systeem bepaalt ToolbarItemPlacement niet alleen de positie, maar ook het visuele uiterlijk van items. Zo past .confirmationAction automatisch de prominente glasstijl toe:

NavigationStack {
    VStack {
        // Content
    }
    .toolbar {
        ToolbarItem(placement: .cancellationAction) {
            Button("Annuleer") { }
            // Krijgt automatisch een subtiele glasstijl
        }

        ToolbarItem(placement: .confirmationAction) {
            Button("Bewaar") { }
            // Krijgt automatisch de prominente glasstijl
        }
    }
}

Apple raadt aan om symbool-gebaseerde knoppen te gebruiken in toolbars, met zowel een afbeelding als een tekstlabel. Het nieuwe ontwerpsysteem geeft duidelijk de voorkeur aan iconen:

Button {
    deelInhoud()
} label: {
    Label("Delen", systemImage: "square.and.arrow.up")
}

Tab Bars: Inkrimpen, Accessories en Meer

De tab bar heeft eerlijk gezegd een van de meest opvallende updates gekregen. In iOS 26 krimpt de tab bar automatisch in wanneer gebruikers scrollen, waardoor meer ruimte vrijkomt voor content. Dat voelt verrassend natuurlijk aan.

Minimaliseergedrag instellen

Met de nieuwe .tabBarMinimizeBehavior()-modifier bepaal je wanneer de tab bar inkrimpt:

TabView {
    Tab("Home", systemImage: "house.fill") {
        HomeView()
    }

    Tab("Zoeken", systemImage: "magnifyingglass") {
        ZoekView()
    }

    Tab("Profiel", systemImage: "person.fill") {
        ProfielView()
    }
}
.tabBarMinimizeBehavior(.onScrollDown)  // Krimpt in bij scrollen
// Andere opties:
// .tabBarMinimizeBehavior(.automatic)  // Systeem bepaalt
// .tabBarMinimizeBehavior(.never)      // Nooit inkrimpen

Bottom Accessory

Een leuke toevoeging in iOS 26 is de bottom accessory — een klein bedieningselement dat onder de tab bar zweeft. Perfect voor mediabediening, voortgangsindicatoren of snelle acties:

TabView {
    Tab("Muziek", systemImage: "music.note") {
        MuziekBibliotheekView()
    }

    Tab("Zoeken", systemImage: "magnifyingglass") {
        ZoekView()
    }
}
.tabViewBottomAccessory {
    HStack {
        Image(systemName: "music.note")
        Text("Nu aan het spelen")
            .font(.caption)
        Spacer()
        Button {
            // Pauzeer/speel
        } label: {
            Image(systemName: "play.fill")
        }
    }
    .padding(.horizontal)
}

Wanneer de tab bar inkrimpt tijdens het scrollen, voegt de bottom accessory zich vloeiend samen met de ingekrompen tab bar. Een mooi voorbeeld van hoe Liquid Glass content en navigatie in harmonie laat samenwerken.

Sheets met Liquid Glass

Sheets hebben ook een behoorlijke update gekregen. In iOS 26 zweven gedeeltelijke sheets boven de interface met afgeronde hoeken die de vorm van het apparaat volgen. Ze gebruiken standaard een Liquid Glass-achtergrond.

Het nieuwe standaardgedrag

struct SheetDemoView: View {
    @State private var toonSheet = false

    var body: some View {
        Button("Toon Sheet") {
            toonSheet = true
        }
        .sheet(isPresented: $toonSheet) {
            VStack(spacing: 20) {
                Text("Liquid Glass Sheet")
                    .font(.title2.bold())

                Text("Deze sheet heeft automatisch een glazen achtergrond en zweeft boven de content.")
                    .multilineTextAlignment(.center)

                Button("Sluit") {
                    toonSheet = false
                }
            }
            .padding()
            .presentationDetents([.medium, .large])
        }
    }
}

Bij de .medium-detent ziet de sheet er prachtig uit: de randen trekken naar binnen, waardoor een zwevend effect ontstaat dat mooi past bij de ronde hoeken van het scherm. Bij .large wordt de achtergrond geleidelijk ondoorzichtig en hecht de sheet zich aan de schermranden.

Tip: Heb je eerder .presentationBackground() gebruikt voor een aangepaste achtergrond? Overweeg om dat te verwijderen. Laat het Liquid Glass-materiaal gewoon z'n ding doen.

Sheet-morphing vanuit toolbar-knoppen

Dit vind ik persoonlijk een van de mooiste nieuwe mogelijkheden: sheets die morphen vanuit de toolbar-knop die ze presenteert. Het creëert een vloeiende transitie die de sheet visueel verbindt met zijn bron:

struct MorphSheetView: View {
    @State private var toonInstellingen = false
    @Namespace private var sheetNamespace

    var body: some View {
        NavigationStack {
            ContentUitView()
                .toolbar {
                    ToolbarItem(placement: .primaryAction) {
                        Button {
                            toonInstellingen = true
                        } label: {
                            Image(systemName: "gear")
                        }
                        .matchedTransitionSource(
                            id: "instellingen",
                            in: sheetNamespace
                        )
                    }
                }
                .sheet(isPresented: $toonInstellingen) {
                    InstellingenView()
                        .navigationTransition(
                            .zoom(
                                sourceID: "instellingen",
                                in: sheetNamespace
                            )
                        )
                }
        }
    }
}

Belangrijk detail: de view met de toolbar moet in een NavigationStack of NavigationSplitView staan om de transitie correct te laten werken.

Knopstijlen: .glass en .glassProminent

Naast de .glassEffect()-modifier biedt iOS 26 twee nieuwe knopstijlen die speciaal zijn ontworpen voor Liquid Glass:

VStack(spacing: 20) {
    // Glazen knop — voor secundaire acties
    Button("Annuleren") {
        annuleer()
    }
    .buttonStyle(.glass)

    // Prominente glazen knop — voor primaire acties
    Button("Bevestigen") {
        bevestig()
    }
    .buttonStyle(.glassProminent)
}

De richtlijn is simpel: .glass voor secundaire acties, .glassProminent voor de primaire actie. Dat creëert een natuurlijke visuele hiërarchie waardoor gebruikers instinctief weten welke knop de belangrijkste is.

Je kunt tinten combineren met knopstijlen voor extra nadruk:

Button("Verwijderen") {
    verwijderItem()
}
.buttonStyle(.glassProminent)
.tint(.red)

Zoekintegratie

De zoekfunctionaliteit in SwiftUI is ook aangepast voor het Liquid Glass-systeem. Op iOS 26 wordt de zoekbalk standaard onderaan het scherm geplaatst:

struct ZoekbareView: View {
    @State private var zoekTekst = ""

    var body: some View {
        NavigationStack {
            List {
                // Content
            }
            .searchable(text: $zoekTekst, prompt: "Zoeken...")
        }
    }
}

Als zoeken niet de primaire ervaring van je scherm is, kun je de nieuwe .searchToolbarBehavior()-modifier gebruiken om het zoekveld te minimaliseren tot een toolbar-knop:

NavigationStack {
    List { /* Content */ }
        .searchable(text: $zoekTekst)
        .searchToolbarBehavior(.minimize)
}

Het systeem kan dit gedrag trouwens ook automatisch toepassen op basis van factoren als schermgrootte of het aantal toolbar-items.

Toegankelijkheid: Een Verantwoordelijkheid

Liquid Glass is visueel prachtig, maar transparante materialen kunnen uitdagingen opleveren voor gebruikers met visuele beperkingen. Daar moeten we als ontwikkelaars rekening mee houden. Gelukkig biedt SwiftUI ingebouwde ondersteuning.

Transparantie verminderen

struct ToegankelijkeGlasView: View {
    @Environment(\.accessibilityReduceTransparency)
    var verminderdTransparantie

    @Environment(\.accessibilityReduceMotion)
    var verminderdBeweging

    var body: some View {
        VStack(spacing: 16) {
            Button("Actie") {
                voerActieUit()
            }
            .padding()
            .glassEffect(
                verminderdTransparantie ? .identity : .regular
            )
        }
    }
}

Het goede nieuws: het Liquid Glass-materiaal past zich al automatisch aan wanneer de gebruiker "Verminder transparantie" heeft ingeschakeld in de systeeminstellingen. Apple's advies is om het systeem dit te laten afhandelen en alleen in te grijpen wanneer het absoluut noodzakelijk is.

Contrast waarborgen

Omdat het glasmateriaal transparant is, moet je ervoor zorgen dat tekst en iconen voldoende contrast hebben met de dynamische achtergrond. Gebruik bij voorkeur systeemkleuren en SF Symbols — die worden automatisch aangepast voor optimale leesbaarheid.

Achterwaartse Compatibiliteit

Natuurlijk draaien niet al je gebruikers direct iOS 26. Voor achterwaartse compatibiliteit kun je een aangepaste view-modifier maken die conditioneel het glaseffect toepast:

struct AdaptiefGlasModifier: ViewModifier {
    func body(content: Content) -> some View {
        if #available(iOS 26.0, *) {
            content.glassEffect(.regular)
        } else {
            content
                .background(.ultraThinMaterial)
                .clipShape(Capsule())
        }
    }
}

extension View {
    func adaptiefGlasEffect() -> some View {
        modifier(AdaptiefGlasModifier())
    }
}

// Gebruik
Button("Actie") { }
    .padding()
    .adaptiefGlasEffect()

De .ultraThinMaterial in combinatie met een clipping-shape biedt een redelijke benadering van het glaseffect op oudere iOS-versies. Het is niet identiek, maar het voelt visueel verwant genoeg.

Best Practices en Veelgemaakte Fouten

Nu je de technische API's kent, laten we het even hebben over hoe je Liquid Glass goed inzet. Want eerlijk gezegd, je kunt hier makkelijk de mist in gaan als je niet oplet.

Doe: Gebruik glas voor navigatie en besturing

Liquid Glass is ontworpen voor de navigatielaag: toolbars, tab bars, knoppen en besturingselementen. Het moet boven de content zweven en de aandacht naar de content eronder leiden.

// Goed: Glaseffect op navigatie-elementen
NavigationStack {
    ScrollView {
        LazyVGrid(columns: kolommen) {
            ForEach(items) { item in
                ItemKaart(item: item)
            }
        }
    }
    .toolbar {
        ToolbarItem(placement: .primaryAction) {
            Button { } label: {
                Image(systemName: "plus")
            }
            // Toolbar-items krijgen automatisch glasstijl
        }
    }
}

Doe niet: Overmatig glaseffect op content

Een veelgemaakte fout — en ik heb het al meerdere keren voorbij zien komen — is het toepassen van glaseffecten op alle lijstrijen of contentkaarten. Dat resulteert in een overbeladen interface die de eigenlijke bedoeling van Liquid Glass ondermijnt:

// Fout: Glaseffect op elke lijstrij
List(items) { item in
    HStack {
        Text(item.naam)
        Spacer()
        Text(item.details)
    }
    .padding()
    .glassEffect()  // Niet doen!
}

Gebruik GlassEffectContainer voor gerelateerde elementen

Plaats gerelateerde glaselementen altijd in een GlassEffectContainer. Glas-op-glas zonder gedeelde container leidt tot inconsistente sampling en visuele artefacten:

// Goed: Gedeelde container
GlassEffectContainer {
    HStack(spacing: 12) {
        Button("A") { }.glassEffect()
        Button("B") { }.glassEffect()
        Button("C") { }.glassEffect()
    }
}

// Fout: Geen container
HStack(spacing: 12) {
    Button("A") { }.glassEffect()
    Button("B") { }.glassEffect()
    Button("C") { }.glassEffect()
}

Verwijder aangepaste achtergronden

Heb je eerder aangepaste achtergronden ingesteld op navigatiebalken, tab bars of sheets? Overweeg dan serieus om die te verwijderen. Het Liquid Glass-materiaal werkt simpelweg het beste wanneer het de onderliggende content kan samplen:

// Verwijder dit soort aanpassingen:
// .scrollContentBackground(.hidden)
// .presentationBackground(Color.white)
// .toolbarBackground(.visible, for: .navigationBar)

// Gebruik in plaats daarvan:
.containerBackground(.clear, for: .navigation)

Een Compleet Voorbeeld: Recepten-app

Laten we alles samenbrengen in een realistisch voorbeeld. Een recepten-app die Liquid Glass volledig benut:

import SwiftUI

struct ReceptenApp: View {
    @State private var zoekTekst = ""
    @State private var toonNieuwRecept = false
    @Namespace private var sheetNamespace

    let recepten = Recept.voorbeeldData

    var body: some View {
        NavigationStack {
            ScrollView {
                LazyVStack(spacing: 16) {
                    ForEach(recepten) { recept in
                        NavigationLink(value: recept) {
                            ReceptKaart(recept: recept)
                        }
                    }
                }
                .padding()
            }
            .navigationTitle("Mijn Recepten")
            .searchable(text: $zoekTekst, prompt: "Zoek een recept...")
            .toolbar {
                ToolbarItemGroup(placement: .bottomBar) {
                    Button { } label: {
                        Label("Filter", systemImage: "line.3.horizontal.decrease")
                    }

                    ToolbarSpacer(.flexible)

                    Button {
                        toonNieuwRecept = true
                    } label: {
                        Label("Nieuw recept", systemImage: "plus")
                    }
                    .matchedTransitionSource(
                        id: "nieuwRecept",
                        in: sheetNamespace
                    )
                }
            }
            .sheet(isPresented: $toonNieuwRecept) {
                NieuwReceptView()
                    .presentationDetents([.medium, .large])
                    .navigationTransition(
                        .zoom(
                            sourceID: "nieuwRecept",
                            in: sheetNamespace
                        )
                    )
            }
            .navigationDestination(for: Recept.self) { recept in
                ReceptDetailView(recept: recept)
            }
        }
    }
}

struct ReceptKaart: View {
    let recept: Recept

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Image(recept.afbeelding)
                .resizable()
                .aspectRatio(16/9, contentMode: .fill)
                .clipShape(RoundedRectangle(cornerRadius: 12))

            Text(recept.naam)
                .font(.headline)

            HStack {
                Label(
                    "\(recept.bereidingstijd) min",
                    systemImage: "clock"
                )
                Spacer()
                Label(
                    recept.moeilijkheid,
                    systemImage: "chart.bar"
                )
            }
            .font(.caption)
            .foregroundStyle(.secondary)
        }
        .padding()
    }
}

In dit voorbeeld werken de toolbar, zoekbalk, sheet en navigatie allemaal samen met het Liquid Glass-systeem. De toolbar-items zweven op een glazen oppervlak, de sheet morpht vanuit de plus-knop, en de zoekbalk past zich vanzelf aan. Dat is het mooie van dit systeem — de onderdelen versterken elkaar.

Prestatie-overwegingen

Liquid Glass-effecten zijn GPU-intensief vanwege de real-time vervaging, lichtbreking en compositing. Daar moet je rekening mee houden, zeker als je veel elementen op het scherm hebt.

  • Beperk het aantal glaseffecten per scherm: Elk glaseffect vereist een aparte render-pass. Te veel tegelijkertijd kan de frame rate negatief beïnvloeden, vooral op oudere apparaten.
  • Gebruik GlassEffectContainer: De container optimaliseert de rendering door meerdere glaseffecten samen te voegen. Dit is niet alleen visueel beter, maar ook performanter.
  • Vermijd glaseffecten in ScrollView-cellen: Honderden cellen met glaseffecten in een scrollbare lijst is simpelweg een recept voor stotteren. Gebruik glaseffecten voor vaste navigatie-elementen, niet voor herhaalde content.
  • Test op echte apparaten: De Simulator geeft geen accuraat beeld van de prestaties. Test altijd op fysieke apparaten, met name oudere modellen zoals de iPhone 15 of eerder.

Conclusie

Liquid Glass is meer dan een cosmetische update — het is een fundamentele verschuiving in hoe Apple-apps eruitzien en aanvoelen. De focus op gelaagdheid, transparantie en vloeiende transities creëert een moderne gebruikerservaring die content centraal stelt.

Als SwiftUI-ontwikkelaar heb je het geluk dat veel van deze schoonheid gratis komt. Compileer je app met Xcode 26 en de standaardelementen krijgen automatisch het nieuwe uiterlijk. Maar om die extra polish toe te voegen die gebruikers echt opvalt, moet je de API's begrijpen die we hier hebben behandeld.

De belangrijkste takeaways:

  • Gebruik .glassEffect() voor navigatie- en besturingselementen, niet voor content
  • Groepeer gerelateerde glaselementen in een GlassEffectContainer
  • Benut morph-transities met .glassEffectID() voor een gepolijste ervaring
  • Respecteer de toegankelijkheidsinstellingen van je gebruikers
  • Verwijder aangepaste achtergronden en laat het glazen materiaal stralen

Met Foundation Models voor on-device AI, de verbeterde concurrency in Swift 6.2 en nu Liquid Glass voor een verbluffende UI — iOS 26 is zonder twijfel een van de meest opwindende releases voor ontwikkelaars in jaren. Tijd om te gaan bouwen.

Over de Auteur Editorial Team

Our team of expert writers and editors.