-
Prepara el escenario con SwiftUI en visionOS
Descubre nuevas y emocionantes API para mejorar ventanas, volúmenes y espacios envolventes en tu app de visionOS. Ajusta el comportamiento de tus escenas cuando se reinician o se bloquean en un lugar. Haz que los volúmenes se adapten a tu entorno con márgenes de recorte y ajuste. Transmite contenido envolvente desde la Mac a Vision Pro. Mejora tus apps existentes basadas en UIKit con volúmenes y espacios envolventes.
Capítulos
- 0:00 - Introducción
- 2:11 - Lanzamiento y bloqueo
- 8:15 - Mejoras volumétricas
- 15:58 - Espacio envolvente
- 22:16 - Puente de escena
- 24:01 - Próximos pasos
Recursos
- Adopting best practices for persistent UI
- Tracking accessories in volumetric windows
- Petite Asteroids: Building a volumetric visionOS game
- Canyon Crosser: Building a volumetric hike-planning app
Videos relacionados
WWDC25
-
Buscar este video…
-
-
4:10 - Disabling restoration
// Disabling restoration WindowGroup("Tools", id: "tools") { ToolsView() } .restorationBehavior(.disabled) -
4:36 - Disabling restoration in UIKit
// Disabling restoration windowScene.destructionConditions = [ .systemDisconnection ] -
5:02 - Specifying launch window
// Specifying launch window @AppStorage("isFirstLaunch") private var isFirstLaunch = true var body: some Scene { WindowGroup("Stage Selection", id: "selection") { SelectionView() } WindowGroup("Welcome", id: "welcome") { WelcomeView() .onAppear { isFirstLaunch = false } } .defaultLaunchBehavior(isFirstLaunch ? .presented : .automatic) // ... } -
6:39 - "suppressed" behavior
// "suppressed" behavior WindowGroup("Tools", id: "tools") { ToolsView() } .restorationBehavior(.disabled) .defaultLaunchBehavior(.suppressed) -
7:44 - Unique window
// Unique window @AppStorage("isFirstLaunch") private var isFirstLaunch = true var body: some Scene { // ... Window("Welcome", id: "welcome") { WelcomeView() .onAppear { isFirstLaunch = false } } .defaultLaunchBehavior(isFirstLaunch ? .presented : .automatic) WindowGroup("Main Stage", id: "main") { StageView() } // ... } -
10:24 - Surface snapping
// Surface snapping @Environment(\.surfaceSnappingInfo) private var snappingInfo @State private var hidePlatform = false var body: some View { RealityView { /* ... */ } .onChange(of: snappingInfo) { if snappingInfo.isSnapped && SurfaceSnappingInfo.authorizationStatus == .authorized { switch snappingInfo.classification { case .table: hidePlatform = true default: hidePlatform = false } } } } -
14:41 - Clipping margins
// Clipping margins @Environment(\.windowClippingMargins) private var windowMargins @PhysicalMetric(from: .meters) private var pointsPerMeter = 1 var body: some View { RealityView { content in // ... waterfall = createWaterfallEntity() content.add(waterfall) } update: { content in waterfall.scale.y = Float(min( windowMargins.bottom / pointsPerMeter, maxWaterfallHeight)) // ... } .preferredWindowClippingMargins(.bottom, maxWaterfallHeight * pointsPerMeter) } -
16:44 - World recenter
// World recenter var body: some View { RealityView { content in // ... } .onWorldRecenter { recomputePositions() } } -
17:58 - Progressive immersion style
// Progressive immersion style @State private var selectedStyle: ImmersionStyle = .progressive var body: some Scene { ImmersiveSpace(id: "space") { ImmersiveView() } .immersionStyle( selection: $selectedStyle, in: .progressive(aspectRatio: .portrait)) } -
18:37 - Mixed immersion style
// Mixed immersion style @State private var selectedStyle: ImmersionStyle = .progressive var body: some Scene { ImmersiveSpace(id: "space") { ImmersiveView() } .immersionStyle(selection: $selectedStyle, in: .mixed) .immersiveEnvironmentBehavior(.coexist) } -
20:14 - Remote immersive space
// Remote immersive space // Presented on visionOS RemoteImmersiveSpace(id: "preview-space") { CompositorLayer(configuration: config) { /* ... */ } } // Presented on macOS WindowGroup("Main Stage", id: "main") { StageView() } -
20:48 - 'CompositorLayer' is a 'CompositorContent'
// 'CompositorLayer' is a 'CompositorContent' struct ImmersiveContent: CompositorContent { @Environment(\.scenePhase) private var scenePhase var body: some CompositorContent { CompositorLayer { renderer in // ... } .onImmersionChange { oldImmersion, newImmersion in // ... } } } -
23:00 - Scene bridging
// Scene bridging import UIKit import SwiftUI // Declare the scenes class MyHostingSceneDelegate: NSObject, UIHostingSceneDelegate { static var rootScene: some Scene { WindowGroup(id: "my-volume") { ContentView() } .windowStyle(.volumetric) } } // Create a request for the scene let requestWithId = UISceneSessionActivationRequest( hostingDelegateClass: MyHostingSceneDelegate.self, id: "my-volume")! // Send a request UIApplication.shared.activateSceneSession(for: requestWithId)
-
-
- 0:00 - Introducción
En visionOS 26 puedes usar nuevas API para escenas ・・ ventanas, volúmenes y espacios envolventes ・・ lo que te permite crear apps más dinámicas e interactivas. Las nuevas funcionalidades incluyen API de ciclo de vida, mejoras volumétricas, '“RemoteImmersiveSpace” para obtener una vista previa en el Apple Vision Pro y API de conexión de escenas para apps de UIKit.
- 2:11 - Lanzamiento y bloqueo
Las nuevas API en visionOS 26 te permiten administrar el inicio de la app y la restauración de escenas, y te permiten crear experiencias más envolventes. Las personas ahora pueden bloquear ventanas, volúmenes y widgets en salas específicas, lo que permite que el contenido virtual persista en su entorno físico. El sistema restaura automáticamente las ventanas bloqueadas cuando alguien regresa a la sala asociada, pero puedes deshabilitar la restauración de elementos transitorios como pantallas de bienvenida o IU dependiente del contexto usando el modificador “restorationBehavior(.disabled).” También puedes personalizar el comportamiento de inicio de la app, eligiendo dinámicamente qué ventana mostrar según el estado de la app con el modificador “defaultLaunchBehavior.” La API de ventana ahora admite ventanas únicas que no se pueden duplicar para evitar la duplicación de interfaces importantes, como ventanas de juegos o videollamadas.
- 8:15 - Mejoras volumétricas
Ahora hay varias mejoras clave para los volúmenes. Puedes usar la API “SurfaceSnappingInfo” para monitorear cuándo las ventanas y los volúmenes se ajustan a superficies físicas, como paredes y mesas. Esta funcionalidad permite experiencias más envolventes porque puedes ajustar la escena según el estado de anclaje, como ocultar plataformas o modificar elementos. ARKit puede proporcionar detalles sobre la superficie a tu app, con el permiso de los usuarios. La actualización también amplía las capacidades de presentación, permitiendo que se originen desde varias fuentes dentro de volúmenes, adornos y RealityKit, con tratamientos visuales especiales para garantizar que permanezcan visibles detrás del contenido 3D. Personaliza el tratamiento visual con el modificador “presentationBreakthroughEffect.” Además, al usar la nueva API Clipping Margins, puedes renderizar contenido no interactivo fuera de los límites de los volúmenes de la escena, mejorando los efectos visuales como cascadas o nubes mientras garantizas que el contenido principal permanezca enfocado y sin obstrucciones. Lee la variable de entorno “windowClippingMargins” para verificar si el sistema otorgó los márgenes.
- 15:58 - Espacio envolvente
Ahora puedes responder a un evento de recentrado del mundo, lo que permite que las personas recalibren la experiencia de la app a su alrededor. Usa el modificador de vista “onWorldRecent” para escuchar este evento y volver a calcular y almacenar posiciones según el nuevo sistema de coordenadas. visionOS 26 también brinda nuevas personalizaciones para los estilos de inmersión. El estilo de inmersión progresiva ahora incluye el formato vertical, que permite experiencias en orientación vertical y mejora la comodidad durante contenido con mucho movimiento. El estilo de inmersión mixta ahora permite que el contenido se combine perfectamente con los entornos del sistema, creando escenarios más envolventes. Usa el modificador de escena “immersiveEnvironmentBehavior” con el comportamiento “coexistir” para habilitar esta combinación. Ahora puedes llevar tus apps a macOS y obtener una vista previa de las escenas directamente como espacios envolventes en el Apple Vision Pro usando “RemoteImmersiveSpaces.” Esta funcionalidad permite una iteración y colaboración más rápidas. Usa “CompositorLayer” para renderizar contenido con Metal en la Mac y mostrarlo en el Apple Vision Pro. La incorporación del tipo de constructor “CompositorContent” significa que puedes usar todo el potencial de SwiftUI con “CompositorLayer”, lo que facilita la creación y administración de experiencias envolventes, tanto remotas como locales, además de permitir el acceso a variables de entorno, la app de modificadores y el uso de variables de estado.
- 22:16 - Puente de escena
Scene Bridging en visionOS 26 permite agregar volúmenes SwiftUI y espacios envolventes a las apps UIKit existentes. Al extender “UIHostingSceneDelegate”, puedes crear escenas SwiftUI y solicitarlas mediante “UISceneSessionActivationRequest”, lo que permite que apps como Safari implementen navegación espacial y otras apps aprovechen las nuevas capacidades de visionOS.
- 24:01 - Próximos pasos
La app de ejemplo permite a las personas crear escenas que se bloquean en un lugar, se ajustan a las superficies y se abren de forma remota desde la Mac. Revisa tus apps y asegúrate de que aprovechen al máximo estas nuevas capacidades.