2024 Spatial ComputingSwiftUI & UI Frameworks
WWDC24 · 13 min · Spatial Computing / SwiftUI & UI Frameworks
Work with windows in SwiftUI
Learn how to create great single and multi-window apps in visionOS, macOS, and iPadOS. Discover tools that let you programmatically open and close windows, adjust position and size, and even replace one window with another. We’ll also explore design principles for windows that help people use your app within their workflows.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 14 snippets
BOT-anist scenes
@main
struct BOTanistApp: App {
var body: some Scene {
WindowGroup(id: "editor") {
EditorContentView()
}
WindowGroup(id: "game") {
GameContentView()
}
.windowStyle(.volumetric)
}
} Creating the movie WindowGroup
@main
struct BOTanistApp: App {
var body: some Scene {
WindowGroup(id: "editor") {
EditorContentView()
}
WindowGroup(id: "game") {
GameContentView()
}
.windowStyle(.volumetric)
WindowGroup(id: "movie") {
MovieContentView()
}
}
} Opening a movie window
struct EditorContentView: View {
(\.openWindow) private var openWindow
var body: some View {
Button("Open Movie", systemImage: "tv") {
openWindow(id: "movie")
}
}
} Pushing a movie window
struct EditorContentView: View {
(\.pushWindow) private var pushWindow
var body: some View {
Button("Open Movie", systemImage: "tv") {
pushWindow(id: "movie")
}
}
} Toolbar
CanvasView()
.toolbar {
ToolbarItem {
Button(...)
}
...
} Title menu
CanvasView()
.toolbar {
ToolbarTitleMenu {
Button(...)
}
...
} Hiding window controls
WindowGroup(id: "movie") {
...
}
.persistentSystemOverlays(.hidden) Creating the controller window
@main
struct BOTanistApp: App {
var body: some Scene {
...
WindowGroup(id: "movie") {
MovieContentView()
}
WindowGroup(id: "controller") {
ControllerContentView()
}
}
} Opening the controller window
struct GameContentView: View {
(\.openWindow) private var openWindow
var body: some View {
...
Button("Open Controller", systemImage: "gamecontroller.fill") {
openWindow(id: "controller")
}
}
} Positioning the controller window
WindowGroup(id: "controller") {
ControllerContentView()
}
.defaultWindowPlacement { content, context in
#if os(visionOS)
return WindowPlacement(.utilityPanel)
#elseif os(macOS)
...
#endif
} Positioning the controller window continued
WindowGroup(id: "controller") {
ControllerContentView()
}
.defaultWindowPlacement { content, context in
#if os(visionOS)
return WindowPlacement(.utilityPanel)
#elseif os(macOS)
let displayBounds = context.defaultDisplay.visibleRect
let size = content.sizeThatFits(.unspecified)
let position = CGPoint(
x: displayBounds.midX - (size.width / 2),
y: displayBounds.maxY - size.height - 20
)
return WindowPlacement(position, size: size)
#endif
} Default size
@main
struct BOTanistApp: App {
var body: some Scene {
...
WindowGroup(id: "movie") {
MovieContentView()
}
.defaultSize(width: 1166, height: 680)
}
} Setting resize limits on the movie window
@main
struct BOTanistApp: App {
var body: some Scene {
...
WindowGroup(id: "movie") {
MovieContentView()
.frame(
minWidth: 680, maxWidth: 2720,
minHeight: 680, maxHeight: 1020
)
}
.windowResizability(.contentSize)
}
} Controller window resizability
@main
struct BOTanistApp: App {
var body: some Scene {
...
WindowGroup(id: "controller") {
ControllerContentView()
}
.windowResizability(.contentSize)
}
} Resources
Related sessions
-
11 min -
16 min -
23 min