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

2022 SwiftUI & UI Frameworks

WWDC22 · 15 min · SwiftUI & UI Frameworks

The craft of SwiftUI API design: Progressive disclosure

Explore progressive disclosure — one of SwiftUI’s core principles — and learn how it influences the design of our APIs. We’ll show you how we use progressive disclosure, discuss how it can support quick iteration and exploration, and help you take advantage of it in your own code.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 21 snippets

Declaration Site Example swift · at 1:59 ↗
struct BookView: View {
    let pageNumber: Int
    let book: Book

    init(book: Book, pageNumber: Int) {
        self.book = book
        self.pageNumber = pageNumber
    }

    var body: some View { ... }
}
Call Site Example swift · at 2:13 ↗
VStack {
    BookView(book: favoriteBook, page: 1)
    BookView(book: savedBook, page: 234)
}
Button Label swift · at 4:18 ↗
Button("Next Page") {
    currentPage += 1
}
Button label expanded swift · at 4:36 ↗
Button {
    currentPage += 1
} label: {
    Text("Next Page")
}
Button label advanced case swift · at 4:43 ↗
Button {
    currentPage += 1
} label: {
    HStack {
        Text("Next Page")
        NextPagePreview()
    }
}
Button label common case swift · at 4:56 ↗
Button("Next Page") {
    currentPage += 1
}
Text example swift · at 5:30 ↗
Text("Hello WWDC22!")
Stacks of Text swift · at 6:12 ↗
VStack {
    Text("Hello WWDC22!")
    Text("Call to Code.")
}
Toolbar swift · at 6:46 ↗
.toolbar {
    Button {
        addItem()
    } label: {
        Label("Add", systemImage: "plus")
    }

    Button {
        sort()
    } label: {
        Label("Sort", systemImage: "arrow.up.arrow.down")
    }

    Button {
        openShareSheet()
    }: label: {
        Label("Share", systemImage: "square.and.arrow.up")
    }
}
Toolbar with explicit placement swift · at 7:20 ↗
.toolbar {
    ToolbarItemGroup(placement: .navigationBarLeading) {
        Button {
            addItem()
        } label: {
            Label("Add", systemImage: "plus")
        }

        Button {
            sort()
        } label: {
            Label("Sort", systemImage: "arrow.up.arrow.down")
        }

        Button {
            openShareSheet()
        }: label: {
            Label("Share", systemImage: "square.and.arrow.up")
        }
    }
}
Advanced use case table swift · at 8:09 ↗
@State var sortOrder = [KeyPathComparator(\Book.title)]

var body: some View {
    Table(sortOrder: $sortOrder) {
        TableColumn("Title", value: \Book.title) { book in
            Text(book.title).bold()
        }
        TableColumn("Author", value: \Book.author) { book in
            Text(book.author).italic()
        }
    } rows: {
        Section("Favorites") {
            ForEach(favorites) { book in
                TableRow(book)
            }
        }
        Section("Currently Reading") {
            ForEach(currentlyReading) { book in
                TableRow(book)
            }
        }
    }
    .onChange(of: sortOrder) { newValue in
        favorites.sort(using: newValue)
        currentlyReading.sort(using: newValue)
    }
}
Simpler table use case swift · at 8:41 ↗
@State var sortOrder = [KeyPathComparator(\Book.title)]

var body: some View {
    Table(sortOrder: $sortOrder) {
        TableColumn("Title", value: \Book.title) { book in
            Text(book.title)
        }
        TableColumn("Author", value: \Book.author) { book in
            Text(book.author)
        }
    } rows: {
        ForEach(currentlyReading) { book in
            TableRow(book)
        }
    }
    .onChange(of: sortOrder) { newValue in
        currentlyReading.sort(using: newValue)
    }
}
Table collection convenience swift · at 9:58 ↗
@State var sortOrder = [KeyPathComparator(\Book.title)]

var body: some View {
    Table(currentlyReading, sortOrder: $sortOrder) {
        TableColumn("Title", value: \.title) { book in
            Text(book.title)
        }
        TableColumn("Author", value: \.author) { book in
            Text(book.author)
        }
    }
    .onChange(of: sortOrder) { newValue in
        currentlyReading.sort(using: newValue)
    }
}
Table string key path convenience swift · at 10:23 ↗
@State var sortOrder = [KeyPathComparator(\Book.title)]

var body: some View {
    Table(currentlyReading, sortOrder: $sortOrder) {
        TableColumn("Title", value: \.title)
        TableColumn("Author", value: \.author)
    }
    .onChange(of: sortOrder) { newValue in
        currentlyReading.sort(using: newValue)
    }
}
Table without sorting swift · at 10:51 ↗
var body: some View {
    Table(currentlyReading) {
        TableColumn("Title", value: \.title)
        TableColumn("Author", value: \.author)
    }
}
Stack example: leading swift · at 13:37 ↗
struct StackExample: View {
    var body: some View {
        HStack { // leading
            Box().tint(.red)
            Box().tint(.green)
            Box().tint(.blue)
        }
    }
}
Stack example: centered swift · at 13:40 ↗
struct StackExample: View {
    var body: some View {
        HStack { // centered
            Spacer()
            Box().tint(.red)
            Box().tint(.green)
            Box().tint(.blue)
            Spacer()
        }
    }
}
Stack example: evenly spaced swift · at 13:42 ↗
struct StackExample: View {
    var body: some View {
        HStack { // evenly spaced
            Spacer()
            Box().tint(.red)
            Spacer()
            Box().tint(.green)
            Spacer()
            Box().tint(.blue)
            Spacer()
        }
    }
}
Stack example: space only between elements swift · at 13:43 ↗
struct StackExample: View {
    var body: some View {
        HStack { // space only between elements
            Box().tint(.red)
            Spacer()
            Box().tint(.green)
            Spacer()
            Box().tint(.blue)
        }
    }
}
Stack example: space only before last element swift · at 13:46 ↗
struct StackExample: View {
    var body: some View {
        HStack { // space only before last element
            Box().tint(.red)
            Box().tint(.green)
            Spacer()
            Box().tint(.blue)
        }
    }
}
Stack example: space only after first element swift · at 13:47 ↗
struct StackExample: View {
    var body: some View {
        HStack { // space only after first element
            Box().tint(.red)
            Spacer()
            Box().tint(.green)
            Box().tint(.blue)
        }
    }
}