Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2025 DesignSwiftUI & UI Frameworks

WWDC25 · 22 min · Design / SwiftUI & UI Frameworks

Build a SwiftUI app with the new design

Explore the ways Liquid Glass transforms the look and feel of your app. Discover how this stunning new material enhances toolbars, controls, and app structures across platforms, providing delightful interactions and seamlessly integrating your app with the system. Learn how to adopt new APIs that can help you make the most of Liquid Glass.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 28 snippets

Segmented Picker swift · at 1:11 ↗
Picker("View", selection: $selection) {
    Text("Map").tag(ViewMode.map)
    Text("List").tag(ViewMode.list)
}
.pickerStyle(.segmented)
Extend background images swift · at 3:59 ↗
// Extend background images

struct LandmarkDetailView: View {
    let landmark: Landmark

    var body: some View {
        ScrollView {
            VStack {
                Image(landmark.backgroundImageName)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .backgroundExtensionEffect()
            }
        }
    }
}
Adding an inspector swift · at 4:23 ↗
// Adding an inspector

NavigationSplitView {
    // sidebar
} detail: {
    // detail
}
.inspector(isPresented: $presentInspector) {
    LandmarkDetailInspectorView(landmark: landmark)
}
Minimize tab bar on scroll swift · at 5:07 ↗
// Minimize tab bar on scroll

TabView {
    // tabs
}
.tabBarMinimizeBehavior(.onScrollDown)
Tab bar accessory swift · at 5:39 ↗
// Tab bar accessory

TabView {
    // tabs
}
.tabBarMinimizeBehavior(.onScrollDown)
.tabViewBottomAccessory {
    MusicPlaybackView()
}

struct MusicPlaybackView: View {
    @Environment(\.tabViewBottomAccessoryPlacement)
    var placement

    var body: some View {
        if placement == .inline {
            // compact layout
        } else {
            // full layout
        }
    }
}
Sheets with presentation detents swift · at 6:20 ↗
// Sheets

CollectionDetailView()
    .sheet(isPresented: $isShowingLandmarksSelection) {
        LandmarksSelectionList()
            .presentationDetents([.height(180), .medium, .large])
    }
Presentation background swift · at 6:53 ↗
// Presentation background

CollectionDetailView()
    .sheet(isPresented: $isShowingLandmarksSelection) {
        LandmarksSelectionList()
            .presentationDetents([.height(180), .medium, .large])
            .presentationBackground(.thickMaterial)
    }
Zoom transition swift · at 7:10 ↗
// Zoom transition

@Namespace private var namespace

ContentView()
    .toolbar {
        ToolbarItem(placement: .bottomBar) {
            Button {
                isPresented = true
            } label: {
                Image(systemName: "map")
            }
            .matchedTransitionSource(
                id: "transition-id", in: namespace)
        }
    }
    .sheet(isPresented: $isPresented) {
        SheetContent()
            .navigationTransition(
                .zoom(
                    sourceID: "transition-id", in: namespace))
    }
Toolbar menus swift · at 7:27 ↗
// Toolbar menus

LandmarkDetailView()
    .toolbar {
        ToolbarItemGroup {
            Button { } label: {
                Image(systemName: "square.and.arrow.up")
            }

            Menu(
                "Collections",
                systemImage: "book.closed"
            ) {
                // menu items
            }
        }
    }
Confirmation dialog swift · at 7:41 ↗
// Confirmation dialog

CollectionDetailView()
    .toolbar {
        Button("Delete", systemImage: "trash") {
            presentDialog = true
        }
        .confirmationDialog(
            "Delete?",
            isPresented: $presentDialog
        ) {
            Button("Delete", role: .destructive) { }
        }
    }
Visually separate toolbar items swift · at 8:26 ↗
// Visually separate toolbar items

struct LandmarkDetailView: View {
    var body: some View {
        ScrollView {
            ScrollContent()
        }
        .toolbar {
            ToolbarItem { ShareLink() }
            ToolbarSpacer(.fixed)
            ToolbarItem { FavoriteButton() }
            ToolbarItem { CollectionsButton() }
            ToolbarSpacer(.fixed)
            ToolbarItem { InspectorToggle() }
        }
    }
}
Toolbar items with flexible spacing swift · at 8:47 ↗
// Toolbar items with flexible spacing

struct InboxView: View {
    var body: some View {
        ScrollView {
            ScrollContent()
        }
        .toolbar {
            ToolbarItem(placement: .bottomBar) {
                FilterPicker()
            }
            ToolbarSpacer(.flexible, placement: .bottomBar)
            DefaultToolbarItem(
                kind: .search, placement: .bottomBar)
            ToolbarSpacer(.fixed, placement: .bottomBar)
            ToolbarItem(placement: .bottomBar) {
                NewMessageButton()
            }
        }
    }
}
Hide shared glass background swift · at 9:07 ↗
// Hide shared glass background

struct HomeView: View {
    var body: some View {
        ContentView()
            .toolbar {
                ToolbarItem {
                    ProfileButton()
                }
                .sharedBackgroundVisibility(.hidden)
            }
    }
}
Toolbar item with a badge swift · at 9:40 ↗
// Toolbar item with a badge

@Environment(ModelData.self) var modelData

CollectionsView()
    .toolbar {
        ToolbarItemGroup {
            Button("Notifications", systemImage: "bell") { }
                .badge(modelData.notifications.count)
            Button("Add", systemImage: "plus") { }
        }
    }
Hard scroll edge effect swift · at 10:57 ↗
// Hard scroll edge effect

ScrollView {
    // content
}
.scrollEdgeEffectStyle(.hard, for: .top)
Search in top-trailing position swift · at 11:44 ↗
// Search in the top-trailing position

struct TopTrailingSearch: View {
    @State private var searchText = ""

    var body: some View {
        NavigationSplitView {
            SidebarContent()
        } detail: {
            DetailContent()
        }
        .searchable(text: $searchText)
    }
}
Minimized search in toolbar swift · at 12:51 ↗
// Minimized search in the toolbar

struct MinimizedSearch: View {
    @State private var searchText = ""

    var body: some View {
        NavigationStack {
            DetailContent()
        }
        .searchable(text: $searchText)
        .searchToolbarBehavior(.minimize)
    }
}
TabView with a search tab swift · at 13:17 ↗
// TabView with a search tab

struct ContentView: View {
    @State private var searchText = ""

    var body: some View {
        TabView {
            // other tabs

            Tab(role: .search) {
                NavigationStack {
                    SearchTabContent()
                }
            }
        }
        .searchable(text: $searchText)
    }
}
Capsule buttons swift · at 14:25 ↗
Button()
    .buttonBorderShape(.capsule)
Button sizes: high density layouts swift · at 15:09 ↗
// Button sizes: high density layouts

VStack {
    Picker("Inspector View Mode", selection: $mode) {
        // options
    }
    .controlSize(.large)

    InspectorStackView()
        .controlSize(.small)
}
Glass button styles swift · at 15:33 ↗
// Prominent glass button
Button("Get Started") { }
    .buttonStyle(.glassProminent)

// Standard glass button
Button("Learn More") { }
    .buttonStyle(.glass)
macOS menu icons swift · at 16:32 ↗
// Menus

Menu("Edit") {
    Section {
        Button("Undo",
               systemImage: "arrow.uturn.backward") { }
        Button("Redo",
               systemImage: "arrow.uturn.forward") { }
    }

    Section {
        Button("Copy",
               systemImage: "document.on.document") { }
        Button("Duplicate",
               systemImage: "plus.square.on.square") { }
    }
}
Concentric rectangle shape swift · at 17:27 ↗
// Concentric rectangle shape

CustomControl()
    .background(.tint, in: .rect(corner: .containerConcentric))
Glass effect swift · at 18:30 ↗
// Glass effect

Label("Desert", systemImage: "sun.max.fill")
    .padding()
    .glassEffect()
Glass effect: custom shape swift · at 18:52 ↗
// Customize shape

Label("Desert", systemImage: "sun.max.fill")
    .padding()
    .glassEffect(in: .rect(cornerRadius: 16))
Glass effect: tinted swift · at 18:59 ↗
// Tinted glass

Label("Desert", systemImage: "sun.max.fill")
    .padding()
    .glassEffect(.regular.tint(.green))
Glass effect: interactive swift · at 19:21 ↗
// Interactive glass

Label("Desert", systemImage: "sun.max.fill")
    .padding()
    .glassEffect(.regular.interactive())
Glass morphing with GlassEffectContainer swift · at 19:51 ↗
// GlassEffectContainer

@Namespace var namespace

GlassEffectContainer {
    VStack {
        if isExpanded {
            VStack(spacing: 16) {
                ForEach(badges) { badge in
                    BadgeLabel(badge: badge)
                        .glassEffect()
                        .glassEffectID(badge.id, in: namespace)
                }
            }
        }

        BadgeToggle()
            .buttonStyle(.glass)
            .glassEffectID("badgeToggle", in: namespace)
    }
}

Resources