2023 EssentialsSpatial ComputingSwiftUI & UI Frameworks
WWDC23 · 26 min · Essentials / Spatial Computing / SwiftUI & UI Frameworks
Meet SwiftUI for spatial computing
Take a tour of the solar system with us and explore SwiftUI for visionOS! Discover how you can build an entirely new universe of apps with windows, volumes, and spaces. We’ll show you how to get started with SwiftUI on this platform as we build an astronomy app, add 3D content, and create a fully immersive experience to transport people to the stars.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 19 snippets
Button
Button("Of course") {
// perform action
} Toggle Favorite
Toggle(isOn: $favorite) {
Label("Favorite", systemImage: "star")
} TabView
TabView {
DogsTab()
.tabItem {
Label("Dogs", systemImage: "pawprint")
}
CatsTab()
.tabItem {
Label("Cats", image: "cat")
}
BirdsTab()
.tabItem {
Label("Birds", systemImage: "bird")
}
} World App
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup("Hello, world") {
ContentView()
}
}
} World TabView
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup("Hello, world") {
TabView {
Modules()
.tag(Tabs.menu)
.tabItem {
Label("Experience", systemImage: "globe.americas")
}
FunFactsTab()
.tag(Tabs.library)
.tabItem {
Label("Library", systemImage: "book")
}
}
}
}
} Stats Grid Section
VStack(alignment: .leading, spacing: 12) {
Text("Stats")
.font(.title)
StatsGrid(stats: stats)
.padding()
.background(.regularMaterial, in: .rect(cornerRadius: 12))
} Fun Fact Button
Button(action: {
// perform button action
}) {
VStack(alignment: .leading, spacing: 12) {
Text(fact.title)
.font(.title2)
.lineLimit(2)
Text(fact.details)
.font(.body)
.lineLimit(4)
Text("Learn more")
.font(.caption)
.foregroundStyle(.secondary)
}
.frame(width: 180, alignment: .leading)
}
.buttonStyle(.funFact) FunFactButtonStyle
struct FunFactButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.background(.regularMaterial, in: .rect(cornerRadius: 12))
.hoverEffect()
.scaleEffect(configuration.isPressed ? 0.95 : 1)
}
} Globe Volume
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup {
Globe()
}
.windowStyle(.volumetric)
.defaultSize(width: 600, height: 600, depth: 600)
}
} Model3D
import SwiftUI
import RealityKit
struct Globe: View {
var body: some View {
Model3D(named: "Earth")
}
} Globe with rotation and controls
struct Globe: View {
var rotation = Angle.zero
var body: some View {
ZStack(alignment: .bottom) {
Model3D(named: "Earth")
.rotation3DEffect(rotation, axis: .y)
.onTapGesture {
withAnimation(.bouncy) {
rotation.degrees += randomRotation()
}
}
.padding3D(.front, 200)
GlobeControls()
.glassBackgroundEffect(in: .capsule)
}
}
func randomRotation() -> Double {
Double.random(in: 360...720)
}
} RealityView
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
} RealityView Gesture
struct Earth: View {
private var pinLocation: GlobeLocation?
var body: some View {
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
}
.gesture(
SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { value in
withAnimation(.bouncy) {
rotation.degrees += randomRotation()
animatingRotation = true
} completion: {
animatingRotation = false
}
pinLocation = lookUpLocation(at: value)
}
)
}
} RealityView Attachments
struct Earth: View {
private var pinLocation: GlobeLocation?
var body: some View {
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
} update: { content, attachments in
if let pin = attachments.entity(for: "pin") {
content.add(pin)
placePin(pin)
}
} attachments: {
if let pinLocation {
GlobePin(pinLocation: pinLocation)
.tag("pin")
}
}
.gesture(
SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { value in
withAnimation(.bouncy) {
rotation.degrees += randomRotation()
animatingRotation = true
} completion: {
animatingRotation = false
}
pinLocation = lookUpLocation(at: value)
}
)
}
} ImmersiveSpace
@main
struct WorldApp: App {
var body: some Scene {
// (other WindowGroup scenes)
ImmersiveSpace(id: "solar-system") {
SolarSystem()
}
}
} Open ImmersiveSpace Action
(\.openImmersiveSpace)
private var openImmersiveSpace
Button("View Outer Space") {
openImmersiveSpace(id: "solar-system")
} ImmersionStyle
@main
struct WorldApp: App {
private var selectedStyle: ImmersionStyle = .full
var body: some Scene {
// (other WindowGroup scenes)
ImmersiveSpace(id: "solar-system") {
SolarSystem()
}
.immersionStyle(selection: $selectedStyle, in: .full)
}
} Starfield
struct Starfield: View {
var body: some View {
RealityView { content in
let starfield = await loadStarfield()
content.add(starfield)
}
}
} SolarSystem
struct SolarSystem: View {
var body: some View {
Earth()
Sun()
Starfield()
}
} Resources
Related sessions
-
26 min -
22 min -
23 min -
28 min -
24 min -
14 min -
16 min -
24 min -
34 min -
32 min -
26 min