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

2022 SwiftUI & UI Frameworks

WWDC22 · 18 min · SwiftUI & UI Frameworks

SwiftUI on iPad: Organize your interface

It’s time to supercharge the interface of your iPad app with SwiftUI lists and tables. We’ll show how you can add selection interactions and context menus and help people who use your app be more productive. We’ll also give you best practices on structuring your navigation and explore how you can avoid modality using split views to ensure a top-notch desktop-class iPad experience. This is the first session in a two-part series. To get the most out of this video, we recommend you have some basic familiarity with SwiftUI. After watching this session, check out "SwiftUI on iPad: Add toolbars, titles, and more" to learn how SwiftUI can help you make even better toolbars for your iPad app.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 6 snippets

Places List swift · at 3:10 ↗
struct PlacesList: View {
    @Binding var modelData: ModelData


    var body: some View {
        List(modelData.places) { place in
            PlaceCell(place)
        }
    }
}
Places Table swift · at 3:18 ↗
struct PlacesTable: View {
    @Binding var modelData: ModelData@State private var sortOrder = [KeyPathComparator(\Place.name)]

    var body: some View {
        Table(modelData.places, sortOrder: $sortOrder) {
            TableColumn("Name", value: \.name) { place in
                PlaceCell(place)
            }
            TableColumn("Comfort Level", value: \.comfortDescription).width(200)
            TableColumn("Noise", value: \.noiseLevel) { place in
                NoiseLevelView(level: place.noiseLevel)
            }
        }
        .onChange(of: sortOrder) {
            modelData.sort(using: $0)
        }
    }
}
Places Table with selection swift · at 10:25 ↗
struct PlacesTable: View {
    @EnvironmentObject var modelData: ModelData
    @State private var sortOrder = [KeyPathComparator(\Place.name)]
    @State private var selection: Set<Place.ID> = []

    var body: some View {
        Table(modelData.places, selection: $selection, sortOrder: $sortOrder) {
            // columns
        }
    }
}
Places Table toolbar additions swift · at 10:26 ↗
Table(modelData.places, selection: $selection, sortOrder: $sortOrder) {
    ...
}
.toolbar {
    ToolbarItemGroup(placement: .navigationBarTrailing) {
        if !selection.isEmpty {
           AddToGuideButton(selection)
        }
    }

    ToolbarItemGroup(placement: .navigationBarLeading) {
        EditButton()
    }
}
Item context menus swift · at 12:34 ↗
// Item context menus

Table(modelData.places, selection: $selection, sortOrder: $sortOrder) {
    ...
}
.contextMenu(forSelectionType: Place.ID.self) { items in
    if items.isEmpty {
        // Empty area
        AddPlaceButton()
    } else {
        if items.count == 1 {
            // Single item
            FavoriteButton(isSet: $modelData.places[items.first!].isFavorite)
        }

        // Single and multiple items
        AddToGuideButton(items)
    }
}
Navigation Split View example swift · at 16:55 ↗
// Navigation Split View example

struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            SidebarView()
       } detail: {
            Text("Select a place")
        }
    }
}

Resources