visionOS Spatial Patterns jenseits des Fensters
Die meisten Apps, die auf visionOS erscheinen, erreichen die Plattform über Apples Kompatibilitätspfad „Designed for iPad”: Das vorhandene iPad-Binary läuft als flaches Panel im 3D-Raum, und der Entwickler setzt ein Häkchen, anstatt eine visionOS-native Erfahrung aufzubauen. Der Pfad ist für den Benutzer in Ordnung (die App funktioniert), verkauft die Plattform aber unter Wert. Die native Oberfläche von visionOS bietet Entwicklern drei Präsentationsmethoden (Windows, Volumes und Immersive Spaces) sowie strukturelle UI-Primitive (Ornaments, Attachments), die das iPad-SDK nicht hat. Apps, die diese übernehmen, fühlen sich nativ an; Apps, die das nicht tun, lesen sich als iPad-on-Vision.
Der Beitrag arbeitet das räumliche Vokabular anhand von Apples Dokumentation durch. Der Rahmen ist „was die Plattform einer SwiftUI-App tatsächlich bietet”, nicht eine visionOS-Einführung. Der Beitrag des Clusters RealityKit and the Spatial Mental Model behandelt die 3D-Inhaltsschicht; dieser Beitrag behandelt die SwiftUI-Oberfläche, die sie umschließt.
TL;DR
- visionOS-Apps setzen sich aus drei Szenentypen zusammen:
WindowGroup(Windows),WindowGroupmit.windowStyle(.volumetric)(Volumes) undImmersiveSpace(Immersive Spaces)1. - Ein Window ist eine 2D-Ebene; ein Volume ist eine begrenzte 3D-Region; ein Immersive Space umgibt den Benutzer. Jeder hat unterschiedliche Regeln: Volumes haben nach der Erstellung eine unveränderliche Größe, Immersive Spaces erfordern explizites Öffnen/Schließen, Windows verhalten sich am ehesten wie auf dem iPad.
- Immersion gibt es in drei Stilen:
.mixed(Inhalte koexistieren mit dem Raum),.full(Raum durch virtuelle Umgebung ersetzt),.progressive(Mittelweg mit peripherer Verankerung)2. - Ornaments sind UI-Ebenen parallel zu einem Window und auf der z-Achse davor. So realisiert visionOS Toolbars und Tab Bars3. Attachments betten SwiftUI-Views in 3D-Inhalte einer RealityView ein, die Brücke zwischen flachem UI und räumlicher Geometrie.
- Das „Panel-App”-Anti-Pattern: Das iPad-UI als Window auszuliefern, ohne Volume, Space oder Ornament zu übernehmen. Der Benutzer kann die App nutzen, aber der eigentliche Wert der Plattform bleibt ungenutzt.
Die drei Szenentypen
Der App-Body einer visionOS-App setzt sich aus Szenen dreier Klassen zusammen. Jede hat ein eigenes mentales Modell für den Benutzer.
Windows: Die 2D-Ebene
WindowGroup erzeugt standardmäßig ein 2D-Window mit dem visionOS-Glasrahmen. Das Window wird im Raum positioniert (das System platziert es vor dem Blickpunkt des Benutzers) und vom Benutzer über systemstandardisierte Gesten verschoben oder skaliert. Aus SwiftUI-Sicht ist ein Window das visionOS-Pendant zu einem macOS-Fenster: eine flache Inhaltsoberfläche mit einem tiefenbewussten Glasmaterial.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Das Standard-Window hat ein Glasmaterial um seinen Inhalt. Apps, die eine vollständig transparente Oberfläche wollen, verwenden .windowStyle(.plain):
WindowGroup {
ContentView()
}
.windowStyle(.plain)
Plain-Style-Windows verlieren den System-Glasrahmen. Verwenden Sie sie, wenn der Inhalt einen eigenen visuellen Container bereitstellt; ansonsten ist die Standardeinstellung korrekt.
Volumes: Die begrenzte 3D-Region
Ein Volume ist eine 3D-Region, die tiefenbewusste Inhalte enthält (ein Modell, eine Szene mit mehreren Objekten, ein UI, das von einer dritten Achse profitiert). Die Volume-Szene ist ebenfalls eine WindowGroup, mit einem anderen Stil:
WindowGroup(id: "globe") {
GlobeView()
}
.windowStyle(.volumetric)
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)
Der Modifier .defaultSize(width:height:depth:in:) gibt die Grenzen des Volumes in realen Einheiten (Metern) an. Standardmäßig sind die Grenzen beim Öffnen festgelegt, und der Benutzer kann das Volume verschieben, aber nicht skalieren. visionOS 2+ hat einen Opt-in-Pfad über .windowResizability(.contentSize) und verwandte APIs für Apps hinzugefügt, die benutzerskalierbare Volumes wünschen; der feste Standard bleibt der häufigste Fall. Die Konsequenz: Wählen Sie die Standardgröße sorgfältig, denn die meisten Volumes sind nicht skalierbar, sofern der Entwickler dies nicht ausdrücklich aktiviert.
Die richtigen Kandidaten für Volumes sind Apps, bei denen die räumliche Begrenzung Teil der Erfahrung ist: eine virtuelle Skulptur, um die der Benutzer herumgeht, ein an einer realen Wand befestigtes Maßband, eine Workout-Szene mit tiefengestaffelten Zielen. Apps, die einfach nur eine größere Leinwand wollen, gewinnen durch ein Volume nichts; ein größeres Window ist die richtige Antwort.
Immersive Spaces: Die Umhüllung
Ein ImmersiveSpace ist eine Szene, die die Umgebung des Benutzers einnimmt. Im Gegensatz zu einem Window oder Volume (beide neben anderen Apps im Shared Space sichtbar) übernimmt ein Immersive Space die Umgebung des Benutzers und blockiert die gleichzeitige Nutzung der Fenster anderer Apps.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "training") {
TrainingScene()
}
.immersionStyle(selection: .constant(.mixed), in: .mixed, .progressive, .full)
}
}
Der Modifier .immersionStyle(...) wählt die Erlebnisstufe:
.mixed. Virtuelle Inhalte erscheinen neben dem realen Raum. Wird für Apps verwendet, bei denen der Benutzer von beiden Kontexten profitiert..progressive. Eine partielle Immersion, die über die Digital Crown nach oben oder unten gedreht wird. Der Benutzer behält die periphere Wahrnehmung des Raumes, während die zentrale Ansicht virtuell ist..full. Der Raum wird durch eine virtuelle Umgebung ersetzt. Wird für vollständig immersive Erlebnisse (Meditation, Trainingssimulationen, Gaming) verwendet.
Das Öffnen eines Immersive Space ist explizit. Die App ruft @Environment(\.openImmersiveSpace) mit der id des Space auf; das System übernimmt die Übergangsanimation und das Schließen jedes konfligierenden Space:
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
Button("Start Session") {
Task {
await openImmersiveSpace(id: "training")
}
}
Pro App kann zu einem Zeitpunkt nur ein Immersive Space aktiv sein. Der Übergang zwischen Spaces (etwa von .mixed zu .full) erfordert das explizite Schließen des alten Space und das Öffnen des neuen.
Ornaments: Die UI-Ebenen um ein Window
Ornaments sind SwiftUI-Views, die an der Kante eines Windows befestigt sind und auf der z-Achse leicht vor der Window-Ebene positioniert werden. So realisiert visionOS Toolbars, Tab Bars und Accessory Controls. Das System nutzt Ornaments durchgehend: die Wiedergabesteuerung in TV, das Segmented Control in Music, die Toolbar in Mail.
ContentView()
.ornament(
attachmentAnchor: .scene(.bottom),
contentAlignment: .center
) {
HStack {
Button("Previous", systemImage: "backward.fill") { ... }
Button("Play", systemImage: "play.fill") { ... }
Button("Next", systemImage: "forward.fill") { ... }
}
.padding()
.glassBackgroundEffect()
}
Der Parameter attachmentAnchor: gibt an, wo das Ornament relativ zum Window sitzt: .scene(.top), .scene(.bottom), .scene(.leading), .scene(.trailing). Die visuelle Gestaltung des Ornaments liegt in der Verantwortung des Entwicklers; .glassBackgroundEffect() erzeugt das visionOS-native Glasmaterial, das zum Rahmen des Windows passt.
Ornaments lösen ein reales Problem auf visionOS: Steuerelemente innerhalb des Windows überfüllen den Inhalt; sie in ein separates Window zu setzen, zwingt den Benutzer dazu, seinen Blick neu auszurichten. Ein Ornament schwebt im peripheren Sichtfeld des Benutzers, ist blickfokussierbar, konkurriert aber nicht mit dem Hauptinhalt um die zentrale Ansicht.
RealityView Attachments: SwiftUI im 3D-Raum
Wenn eine App SwiftUI-Views innerhalb einer 3D-Szene benötigt (ein Label an einem 3D-Modell, ein Button, der neben einem virtuellen Objekt schwebt, eine Messanzeige, die an einer realen Oberfläche befestigt ist), ist die Brücke der Attachments-Mechanismus von RealityView.
RealityView { content, attachments in
let model = ModelEntity(...)
content.add(model)
if let label = attachments.entity(for: "label") {
label.position = [0, 0.5, 0]
model.addChild(label)
}
} attachments: {
Attachment(id: "label") {
Text("Vintage Globe, 1872")
.padding()
.glassBackgroundEffect()
}
}
Der attachments:-Closure deklariert SwiftUI-Views mit stabilen Identifikatoren. Innerhalb des Haupt-RealityView-Closures ruft attachments.entity(for:) die View als 3D-Entity ab, die im Koordinatenraum der Szene positioniert werden kann. Die View nimmt am Aktualisierungszyklus von SwiftUI teil (Zustandsänderungen rendern die View neu), während sie als texturierte Ebene in der 3D-Szene gerendert wird.
Der Mechanismus ist der richtige für jedes In-World-UI: ein Label, das einem bewegten Objekt folgt, eine Messanmerkung, ein kontextueller Button. Das Authoring der SwiftUI-View ändert sich nicht; die 3D-Positionierung erfolgt auf der RealityView-Ebene.
Das „Panel-App”-Anti-Pattern
Der häufigste Auslieferungsfehler auf visionOS ist die Panel-App: eine iPad-App, die über die „Designed for iPad”-Kompatibilität auf visionOS landet und als einzelnes Window ohne Volume, ohne Immersive Space und ohne Ornaments ausgeliefert wird. Die App funktioniert, aber sie verdient sich die Plattform nicht.
Drei Signale, dass eine App eine Panel-App ist:
Eine einzelne Window-Szene. Kein .windowStyle(.volumetric), kein ImmersiveSpace deklariert. Die App ist eine flache Oberfläche, und das war’s.
Keine Ornaments übernommen. Die Tab Bar der App lebt innerhalb des Window-Inhalts statt außerhalb. Das Ergebnis ist überfüllter als bei einer visionOS-nativen App mit derselben Inhaltsdichte.
Keine räumlichen Funktionen. Die App nutzt die dritte Achse für nichts: keine 3D-Modelle in einem Volume, keine Umgebungsszene in einem Space, kein z-positioniertes UI über Attachments. Die App macht dasselbe wie auf dem iPad, nur schwebend.
Panel-Apps sind keine Fehlschläge; sie sind die richtige Entscheidung für Inhaltskategorien, die nicht von Spatial Computing profitieren (eine Chat-App, eine Notiz-App, ein Einstellungs-Tool). Der Fehlermodus besteht darin, eine Panel-App auszuliefern und für sie visionOS-native Autorität zu beanspruchen. Der Beitrag des Clusters Apple Platform Matrix argumentiert, dass Plattformeinschluss eine Produktentscheidung ist; bei visionOS lautet die Frage: „Sollte sich diese App die räumliche Oberfläche verdienen, oder reicht das Panel?”
Häufige Fehler
Drei Muster, die zu schlechter visionOS-UX führen:
Volumes, die eigentlich 2D-Inhalte mit Tiefen-Padding sind. Ein „3D”-UI, das ein Volume füllt, aber flache Ebenen darin rendert, verschwendet Platz. Volumes sind für 3D-Inhalte; flache Inhalte gehören in ein Window.
Ein Immersionsstil, der gegen den Anwendungsfall arbeitet. Eine Meditations-App, die nur .full-Immersion ausliefert, zwingt den Benutzer für kurze Sitzungen aus seiner Umgebung. Eine Trainings-App, die nur .mixed ausliefert, geht für vollständig fokussierte Übungen nicht weit genug. Passen Sie den Immersionsstil an die tatsächliche Sitzung des Benutzers an.
Ornaments, die mit dem Inhalt konkurrieren. Ornaments sind per Design peripher. Ein Ornament, das zentrale Aufmerksamkeit fordert (eine blinkende Farbe, animierte Bewegung), verfehlt seinen Zweck. Verwenden Sie Ornaments für stabile, auf einen Blick erfassbare Steuerelemente.
Was dieses Muster für visionOS-Apps bedeutet
Drei Erkenntnisse.
-
Wählen Sie den Szenentyp nach dem mentalen Modell des Benutzers, nicht nach dem, was einfach ist. Eine flache Liste von Elementen ist ein Window. Ein 3D-Modell, das der Benutzer inspiziert, ist ein Volume. Eine umgebende Umwelt ist ein Immersive Space. Diese in einer App zu mischen (ein Window mit einem auf Anforderung geöffneten Volume, ein Immersive Space, der über einen Button im Window erreichbar ist), ist das visionOS-native Muster.
-
Übernehmen Sie Ornaments für Toolbars und Accessory-UI. Ornaments sind die Art, wie visionOS kommuniziert „dieses UI ist ergänzend”; Toolbars in den Window-Inhalt zu setzen, liest sich als iPad-on-Vision. Die Integration ist klein und der visuelle Unterschied ist groß.
-
Verwenden Sie Attachments für In-World-UI in RealityView. Labels an 3D-Objekten, Buttons in der Nähe virtueller Inhalte, kontextuelle Anzeigen. Die Brücke zwischen SwiftUI und 3D-Raum ist gelöst; der Fehlermodus besteht darin, sie nicht zu nutzen und stattdessen mit Ad-hoc-3D-Textrendering zu enden.
Der vollständige Apple Ecosystem Cluster: typisierte App Intents; MCP-Server; die Routing-Frage; Foundation Models; die Unterscheidung Runtime vs. Tooling LLM; drei Oberflächen; das Single-Source-of-Truth-Muster; Two MCP Servers; Hooks für Apple-Entwicklung; Live Activities; die watchOS-Runtime; SwiftUI-Internals; RealityKits räumliches mentales Modell; SwiftData-Schemadisziplin; Liquid-Glass-Muster; Multi-Plattform-Auslieferung; die Plattform-Matrix; Vision Framework; Symbol Effects; Core ML-Inferenz; Writing Tools API; Swift Testing; Privacy Manifest; Accessibility als Plattform; SF Pro-Typografie; worüber zu schreiben ich mich weigere. Der Hub befindet sich in der Apple Ecosystem Series. Für den breiteren Kontext zu iOS mit AI-Agenten siehe den iOS Agent Development Guide.
FAQ
Was ist der Unterschied zwischen einem Volume und einem Immersive Space?
Ein Volume ist eine begrenzte 3D-Region, die im Shared Space neben anderen Apps lebt. Der Benutzer kann darum herumgehen, das System rahmt es ein, und die Windows anderer Apps bleiben sichtbar. Ein Immersive Space umgibt den Benutzer, übernimmt die Umgebung und verhindert die gleichzeitige Nutzung anderer Apps. Volumes sind für „schau dir dieses 3D-Ding an”; Spaces sind für „sei in dieser Umgebung”.
Kann ich mehrere Volumes gleichzeitig öffnen?
Ja. Mehrere WindowGroup-mit-.volumetric-Szenen können gleichzeitig geöffnet sein, jede mit eigener Größe und eigenem Inhalt. Das System positioniert sie unabhängig im Raum.
Kann ich mehrere Immersive Spaces gleichzeitig öffnen?
Nein. Pro App kann zu einem Zeitpunkt nur ein Immersive Space aktiv sein. Das Wechseln zwischen Spaces erfordert das explizite Schließen des aktuellen und das Öffnen des neuen über @Environment(\.openImmersiveSpace) und @Environment(\.dismissImmersiveSpace).
Ist die Volume-Größe wirklich unveränderlich?
Volume-Grenzen sind beim Öffnen standardmäßig fest; der Rahmen der visionOS-HIG ist, dass Volumes spezifische 3D-Inhalte mit beabsichtigten Grenzen darstellen und beliebiges Skalieren durch den Benutzer den vorgesehenen Maßstab des Inhalts verzerren würde. visionOS 2+ hat ein Entwickler-Opt-in für skalierbare Volumes über .windowResizability(.contentSize) und verwandte APIs hinzugefügt, sodass Apps, die benutzerskalierbare räumliche Container benötigen, dies anfordern können. Die meisten Volumes werden mit dem festen Standard ausgeliefert, was die HIG weiterhin für Inhalte mit spezifischem Maßstab (eine virtuelle Skulptur, ein physisch dimensioniertes Modell) empfiehlt.
Wie füge ich einem visionOS-Window eine Tab Bar hinzu?
Verwenden Sie eine TabView innerhalb des Windows für In-Content-Tabs (das iPad-Style-Muster) oder ein Ornament mit benutzerdefinierten Button-Reihen für ein visionOS-natives peripheres Tab-UI. Den Ornament-Pfad nutzen Apples eigene Apps (Music, Mail), und er fühlt sich für visionOS-Benutzer am nativsten an.
Können RealityView-Attachments mit Hand-Tracking interagieren?
Ja. Die Attachments sind, sobald positioniert, 3D-Entitäten und nehmen am gleichen Gesten- und Hit-Testing-System teil wie andere RealityKit-Entitäten. Tap-, Drag- und Hover-Gesten werden über die Standard-Gestenmodifier von SwiftUI angebunden; der RealityKit-Beitrag des Clusters behandelt die Integrationsmuster für Hand-Tracking.
Quellen
-
Apple Developer: Meet SwiftUI for spatial computing (WWDC 2023 Session 10109). Einführung von WindowGroup, volumetric WindowGroup und ImmersiveSpace als die drei visionOS-Szenentypen. ↩
-
Apple Developer Documentation:
ImmersionStyle. Die drei Immersionsstile (.mixed,.progressive,.full) und der Modifier.immersionStyle(selection:in:)API. ↩ -
Apple Developer Documentation:
ornament(visibility:attachmentAnchor:contentAlignment:ornament:). Der SwiftUI-View-Modifier, der einem Window eine Ornament-UI-Ebene mit dem angegebenen Anker hinzufügt. ↩ -
Apple Developer: Go beyond the window with SwiftUI (WWDC 2023 Session 10111). Die Session zu Volumes, Immersive Spaces und den Mustern, um über flaches Panel-UI auf visionOS hinauszugehen. ↩
-
Apple Developer Documentation: Creating an immersive space in visionOS with SwiftUI. Der End-to-End-Leitfaden zum Definieren und Öffnen von Immersive Spaces. ↩