View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Videos

Abrir menú Cerrar menú
  • Colecciones
  • Temas
  • Todos los videos
  • Información

Más videos

  • Información
  • Resumen
  • Transcripción
  • Código
  • Conoce el diseño espacial de SwiftUI

    Explora nuevas herramientas para crear experiencias espaciales con SwiftUI. Conoce los conceptos básicos de las vistas 3D SwiftUI en visionOS, personaliza diseños existentes con alineaciones de profundidad y usa modificadores para rotar y posicionar vistas en el espacio. Descubre cómo usar contenedores espaciales para alinear vistas en el mismo espacio 3D, lo que te ayudará a crear apps envolventes y atractivas.

    Capítulos

    • 0:00 - Introducción
    • 2:47 - Vistas 3D
    • 7:18 - Alineaciones de profundidad
    • 11:41 - Diseño de rotación
    • 16:28 - Contenedores espaciales
    • 19:22 - Próximos pasos

    Recursos

    • Canyon Crosser: Building a volumetric hike-planning app
    • Human Interface Guidelines: Designing for visionOS
      • Video HD
      • Video SD

    Videos relacionados

    WWDC25

    • Mejor juntos: SwiftUI y RealityKit

    WWDC22

    • Compose custom layouts with SwiftUI

    WWDC19

    • Building Custom Views with SwiftUI
  • Buscar este video…

    Te damos la a “Conoce el diseño espacial de SwiftUI”. Soy Trevor, ingeniero del equipo de SwiftUI. En esta sesión, exploraremos técnicas para crear experiencias espaciales increíbles con SwiftUI.

    Estuve poniendo en práctica las nuevas capacidades de diseño espacial de SwiftUI, ampliando una app llamada BOT-anist.

    La app te permite personalizar divertidos robots a partir de varios bloques, colores y materiales. Luego, podrás usar tus nuevos bots para cuidar tu propio jardín virtual. Me encanta crear estos pequeños robots y estuve trabajando en nuevas vistas para catalogar mis creaciones.

    Ahora, no solo puedes personalizar robots, sino que también puedes guardarlos y coleccionarlos.

    Te mostraré algunas nuevas escenas 3D para ver los robots. Creé todas estas experiencias con SwiftUI.

    Si alguna vez creaste experiencias 3D en visionOS, seguro ya usaste RealityKit.

    RealityKit es una gran estructura para crear apps 3D, en especial las que tienen comportamientos complejos, como simulaciones físicas.

    Si vienes de un entorno de SwiftUI, podrás incorporar la sintaxis declarativa que ya conoces. Seguro no necesitarás toda la potencia de RealityKit en toda tu app. Ahora, en visionOS 26, puedes usar las herramientas e ideas de diseño 2D de SwiftUI para crear apps 3D.

    El diseño de SwiftUI ofrece compatibilidad integrada para animaciones, ajustes de tamaño y administración de estados, por lo que, si elimino un bot del carrusel, SwiftUI puede animar las posiciones y los tamaños de los demás para tener más o menos espacio.

    Al cambiar el tamaño del volumen, el carrusel y los robots se redimensionan de forma automática. Veamos las nuevas herramientas que usé para crear estos arreglos.

    Estas extensiones 3D del sistema de diseño de SwiftUI se basan en conceptos de diseño 2D existentes.

    Si no trabajaste con diseños de SwiftUI, consulta “Building custom views with SwiftUI” y “Compose custom layouts with SwiftUI” antes de avanzar. Aquí, veremos lo básico sobre vistas 3D de SwiftUI en visionOS, cómo personalizar diseños existentes con alineaciones de profundidad, rotation3DLayout, un nuevo modificador para rotar vistas en el sistema de diseño y SpatialContainer y spatialOverlay para alinear vistas en un espacio 3D.

    Hablemos de las vistas y el sistema de diseño.

    Para cada vista de tu app, SwiftUI calcula el ancho, la altura y la posición X e Y.

    Algunas vistas, como las imágenes no ajustables, tienen un marco fijo del mismo tamaño del componente.

    Algunas vistas, como esta Color, tienen marcos flexibles y ocupan todo el espacio que les brinda el contenedor.

    Los diseños integran a sus subelementos en un marco final. El marco de esta VStack, que está en amarillo, está determinado por el espacio que hay para él y los subelementos que contiene. Aquí, la altura es la suma de las dos vistas de imagen del interior. visionOS se comporta igual, pero allí las vistas son 3D. El sistema de diseño tiene los mismos comportamientos, solo que aplicados a tres dimensiones, no a dos.

    Para cada una de las vistas, además del ancho y la altura, SwiftUI también calcula la profundidad y la posición Z. Suelo usar el modificador border para visualizar marcos 2D en iOS.

    Aquí creé mi propio modificador debugBorder3D para visualizar marcos 3D en visionOS. Te mostraré cómo creé este modificador al final del video, con algunas API que veremos mientras tanto.

    debugBorder3D muestra que Model3D se comporta como una imagen, pero en tres dimensiones, y ocupa un ancho, una altura y una profundidad fijos. Todas las vistas son 3D, pero algunas tienen profundidad cero.

    Muchas de las vistas con las que creas experiencias planas, como Image, Color y Text, tienen profundidad cero, es decir, se comportan igual que en iOS.

    Algunas vistas tienen profundidad flexible, como Color, que ocupa todo el ancho y la altura disponibles que tenga por defecto. En visionOS, ciertas vistas, como RealityView, ocupan toda la profundidad disponible que tengan por defecto.

    GeometryReader3D tiene el mismo comportamiento, así como Model3D, con el modificador resizable aplicado, que hizo que nuestro robot se estire para ajustarlo al ancho de la ventana. Pero luce un poco estirado en esta relación de aspecto. Quiero que recupere sus proporciones originales y que también se ajuste al espacio disponible.

    Puedo usar el nuevo modificador, scaledToFit3D, además de resizable(), para que mi robot mantenga la relación de aspecto y ajuste su tamaño para adaptarse al ancho, la altura y la profundidad disponibles.

    Pero ¿de dónde proviene esta profundidad disponible? Como el ancho y la altura, el contenido de Windows recibe una propuesta de profundidad raíz. El ancho y la altura pueden ajustarse pero esta propuesta es fija para Windows. Fuera de esta profundidad, el sistema puede recortar el contenido.

    Un volumen propone un ancho, altura y profundidad a su contenido, pero en un volumen, la profundidad también es ajustable. Consulta “Designing for visionOS” en las Human Interface Guidelines para obtener más detalles de cuándo usar un volumen o una ventana.

    Algunas vistas alteran estas propuestas de profundidad en vistas contenidas. Al igual que una VStack compone la altura de sus subvistas, ZStack compone las profundidades. La profundidad de esta ZStack es la necesaria para colocar ambos robots uno delante del otro.

    Mientras que VStack puede proponer distintas alturas a sus subvistas según factores como el espacio disponible, la cantidad y el tipo de subelementos, ZStack puede proponer distintas profundidades a sus subelementos en función de los mismos factores. Aquí, RealityView lleva al robot hacia adelante en la ZStack, llenando toda la profundidad disponible en la escena.

    Los tipos de Layout y Stack existentes son 3D en visionOS y usarán comportamientos predeterminados adecuados para la profundidad. Aquí, HStack recibirá una propuesta de profundidad de su contenedor y establecerá su propia profundidad para ajustarse a los modelos que contiene.

    La HStack también alinea las espaldas de estos robots por defecto.

    A este concepto lo llamamos alineación de profundidad. Es una nueva herramienta que deja personalizar los tipos de Layout SwiftUI existentes para que se adapten a las vistas 3D y la profundidad. Si trabajaste con alineaciones verticales u horizontales, estas te serán familiares. Quiero crear una nueva ventana volumétrica para mostrar mis robots favoritos con su nombre y descripción. Actualicemos el código del Model3D del robot para que sea más reusable.

    Empiezo con un Model3D que se puede ajustar.

    Lo refactorizo para usar el nuevo tipo Model3DAsset, que me permite precargar el modelo de mi robot. Todo esto lo incluyo en una nueva ResizableRobotView, que puedo usar en toda la app. También elimino el debugBorder3D por ahora.

    Ahora crearé un RobotProfile con una VStack que contiene una ResizableRobotView y una RobotNameCard con algunos detalles sobre el bot.

    Pero hay un problema.

    Cuesta leer la tarjeta porque está en la parte posterior de la VStack y se pierde un poco detrás del modelo del robot.

    En HStack puedes alinear el contenido en el borde central,

    superior, o inferior, y aquí puedes definir cómo alinear vistas en el eje de profundidad en visionOS.

    Por defecto, los tipos de Stack y Layout usan una alineación posterior. Ahora, en visionOS 26, puedes personalizar DepthAlignments en cualquier Layout.

    Actualizaré el RobotProfile para usar VStackLayout.

    Así puedo aplicar el modificador depthAlignment. Solicito la alineación .front.

    También puedes usar las guías .center o .back.

    Creo que la posición frontal es la mejor para que la tarjeta sea legible.

    Nunca olvidaré a Zapper Ironheart y su amplio conocimiento de datos oscuros.

    Las alineaciones frontal, posterior y central son una gran opción si deseas usar una de esas tres configuraciones estándar. Pero ¿y si necesitas algo más complejo que esos comportamientos?

    Creé un volumen para mostrar mis tres robots favoritos con tres de estas vistas de perfil en una HStack. Greg-gear Mendel es mi robot favorito y quiero que destaque un poco más que los otros en esta vista.

    Estaba pensando en una especie de podio de profundidad en el que cuanto más me guste un robot, más cerca estará de mí. Entonces el Robot 1 estará más cerca, luego el 2 y luego el 3.

    Desde arriba, quiero que se vea como que la parte posterior del primer robot está alineada en profundidad con el centro del segundo robot y el frente del tercero. Necesitaré una alineación de profundidad personalizada para hacerlo.

    Definiré una estructura que se ajuste al protocolo DepthAlignmentID.

    Implemento el único requisito, el valor predeterminado de la alineación.

    Uso la guía de alineación frontal como predeterminada para DepthPodiumAlignment.

    Luego defino una constante estática en la alineación de profundidad que usa este nuevo tipo DepthAlignmentID.

    Ahora puedo usar esta guía de depthPodium como alineación de profundidad en la HStack que contiene cada robot.

    El frente de todos los robots quedará alineado y le dará el valor predeterminado especificado para esta guía.

    Ahora personalizaré la guía de profundidad depthPodium del Robot 2 para alinear su centro con esta guía.

    Modificaré el Robot 1 y alinearé su parte posterior con la guía depthPodium.

    El Robot 3 seguirá usando la guía frontal como predeterminada para la alineación.

    Así se ve en el simulador.

    Con los bots en distintas profundidades, nadie dudará que Greg-gear Mendel es mi preferido.

    Las alineaciones de profundidad son ideales para modificar la posición de profundidad en diseños existentes. Pero ¿qué sucede si quieres crear algo con aún más profundidad? El diseño de rotación es una gran herramienta para usos 3D más avanzados. Quizá ya conozcas el modificador rotation3DEffect, que aplica un efecto visual a una vista para que rote sobre un eje determinado. Es ideal para rotaciones básicas. Pero si colocamos nuestro modelo en una HStack con una tarjeta descriptiva al lado y rotamos el cohete 90° sobre el eje Z, choca con la tarjeta y empieza a salirse del volumen.

    Si aplicamos esquemas de depuración antes y después del efecto de rotación, es un poco más fácil entender qué está pasando. El esquema rojo continuo rota debido al efecto, pero el azul discontinuo muestra dónde está la geometría del cohete según el sistema de diseño. La HStack se dimensiona y coloca su contenido con relación al marco azul. Pero no se alinean. Esto se debe a que los efectos visuales no afectan el diseño. Es decir, la HStack no reconoce la geometría rotada del cohete cuando se usa rotation3DEffect.

    Esto aplica a todos los efectos visuales, incluidos scaleEffect

    y offset. En todos estos casos, el sistema no ajustará el tamaño ni la ubicación de las vistas debido a estos modificadores. Esto es genial cuando quieres animar una vista sin afectar los marcos de otras que la rodean.

    Pero ¿qué pasa si lo haces? ¿Cómo podemos arreglar este cohete rotado?

    Buenas noticias. En visionOS 26, presentamos un nuevo modificador rotation3DLayout, que modifica el marco de una vista rotada en el sistema de diseño. Cuando lo aplico a mi modelo de cohete, la HStack puede ajustar su tamaño y ubicación para dar al cohete y a la tarjeta suficiente espacio.

    rotation3DLayout admite rotaciones en cualquier ángulo y eje, por lo que puedo rotar mi cohete a 45° para que parezca como si estuviera despegando hacia el espacio.

    Aplico un esquema de depuración antes y después de rotation3DLayout. Esto muestra el marco rotado del cohete en rojo. El esquema azul muestra el marco de la vista modificada en el sistema de diseño. Observa que el cuadro delimitador azul se alinea con el eje del contenedor y se ajusta al marco rotado rojo.

    Ahora veamos cómo podemos usar rotation3DLayout para crear el carrusel de robots que te mostré al inicio del video.

    Empezaré tomando prestado el RadialLayout de “Compose custom layouts with SwiftUI”.

    Este tipo de Layout personalizado coloca las vistas en un círculo con la circunferencia definida por el ancho y la altura disponibles.

    MyRadialLayout se creó en un principio para colocar vistas 2D en iOS, pero funciona muy bien en visionOS.

    Incluso si queremos colocar modelos 3D de robots y no imágenes 2D de mascotas, podemos colocar los modelos 3D en este diseño personalizado con ForEach.

    Se ve bien, pero sigue siendo una experiencia vertical. Quiero que mis robots tenga una orientación horizontal en el volumen.

    Aplicaré un rotation3DLayout al diseño radial rotando la vista 90° sobre el eje X. Lo que antes era la altura del carrusel ahora definirá la profundidad de la vista rotada en el sistema de diseño. Mi carrusel está bien orientado ahora, pero mis robots están acostados, durmiendo en el trabajo.

    Para pararlos, podemos rotar cada robot en sentido contrario en el ForEach con otro rotation3DEffect de -90° sobre el eje X. Estos robots somnolientos ahora están en posición de atención. Solo queda una cosa por arreglar. El carrusel está alineado al centro dentro de la altura del volumen. Me gustaría que quede al ras de la placa base del volumen.

    Esto es más fácil de notar si aplicamos un debugBorder3D a todo el carrusel.

    Puedo usar la misma estrategia que usaría para un diseño 2D. Quiero llevar el carrusel hacia abajo en una VStack con un Spacer encima. Mis robots ahora se ven geniales en la parte inferior del volumen. Hablemos las herramientas de diseño 3D SpatialContainer y spatialOverlay. Hay algo más que me gustaría agregar al carrusel de robots. Con un toque, el robot se debería seleccionar y mostrar un menú de controles y un anillo en la parte inferior para indicar que está seleccionado. El anillo también está representado como un Model3D. Quiero que el anillo ocupe el mismo espacio 3D que el robot. No que se apilen sobre un eje. Necesito una herramienta que ubique a los modelos en el mismo espacio 3D.

    La nueva API SpatialContainer permite colocar varias vistas en el mismo espacio 3D como una serie de muñecas rusas.

    Puedes aplicar una alineación tridimensional a todas las vistas. Aquí alineamos a todos los subelementos según su guía de alineación bottomFront.

    Y aquí, según su guía topTrailingBack.

    spatialOverlay es una herramienta similar que permite superponer una vista en el mismo espacio 3D que otra.

    Al igual que SpatialContainer, admite alineaciones 3D.

    Solo tengo dos vistas para alinear, el robot y el anillo de selección. En realidad, solo me importa la geometría del robot. Quiero ajustar el tamaño del anillo para que se adapte al del robot. Usaré una spatialOverlay para implementar las imágenes del robot seleccionado.

    Agregaré un modificador spatialOverlay al modelo de robot. Si figura seleccionado, coloca la vista del anillo ajustable como su contenido. Usaré la alineación .bottom para alinear la parte inferior del anillo con la parte inferior del robot.

    Creo que el carrusel de robots se ve genial. Y es fácil hacer cosas aún mejores con todas las API componibles de SwiftUI.

    Repasemos todo lo que aprendimos al implementar debugBorder3D.

    Aquí está el modificador que mostré antes aplicado a un Model3D.

    Defino un método debugBorder3D} como una extensión de View. Aplico una spatialOverlay al contenido modificado para representar el borde en el mismo espacio 3D} que la vista a la que se aplica.

    Coloco una ZStack dentro que contiene un borde 2D, un espaciador y otro borde 2D.

    Luego, aplico un rotation3DLayout a toda la ZStack para colocar bordes en las caras derecha e izquierda de la vista.

    Por último, coloco esta ZStack interna dentro de otra ZStack con bordes 2D para las caras frontal y posterior. Con esto tenemos bordes en todos los lados.

    Me encanta poder combinar estos modificadores 2D de SwiftUI con nuevas API 3D para crear algo totalmente nuevo.

    Hay análogos 3D para muchas de las herramientas de diseño y modificadores que quizás ya usaste en contextos 2D. Consulta la documentación para conocer más sobre estas API.

    SwiftUI es una gran herramienta para crear apps 3D, pero en muchos casos conviene usar RealityKit, a menudo combinando ambas en la misma app.

    Ahora que tu contenido de SwiftUI es 3D, deberá interactuar con el código de RealityKit. Mis amigos Maks y Amanda crearon unas incorporaciones sorprendentes para BOT-anist con ambas estructuras. Consulta “Better Together: SwiftUI and RealityKit” para más información. No puedo esperar a ver cómo luce tu app en 3D.

    • 3:02 - Robot Image Frame

      // Some views have fixed frames
      
      Image("RobotHead")
        .border(.red)
    • 3:05 - Color Frame

      // Some views have flexible frames
      
      Color.blue
        .border(.red)
    • 3:15 - Layout Composed Frame

      // Layouts compose the frames of their children
      
      VStack {
        Image("RobotHead")
          .border(.red)
        Image("RobotHead")
          .border(.red)
      }
      .border(.yellow)
    • 4:00 - Model3D Frame

      // Some views have fixed depth
      
      Model3D(named: "Robot")
        .debugBorder3D(.red)
    • 4:25 - Zero Depth Views

      // Many views have 0 depth
      
      HStack {
        Image("RobotHead")
          .debugBorder3D(.red)
        Text("Hello! I'm a piece of text. I have 0 depth.")
          .debugBorder3D(.red)
        Color.blue
          .debugBorder3D(.red)
          .frame(width: 200, height: 200)
      }
    • 4:41 - RealityView Depth

      // RealityView takes up all available space including depth
      
      RealityView { content in
        // Setup RealityView content
      }
      .debugBorder3D(.red)
    • 4:56 - GeometryReader3D Depth

      // GeometryReader3D uses all available depth
      
      GeometryReader3D { proxy in
        // GeometryReader3D content
      }
      .debugBorder3D(.red)
    • 5:01 - Model3D scaledToFit3D

      // Scaling a Model3D to fit available space
      
      Model3D(url: robotURL) {aresolved in
        resolved.resizable()
      }aplaceholder: {
        ProgressView()
      }
      .scaledToFit3D()
      .debugBorder3D(.red)
    • 6:15 - ZStack depth

      // ZStack composes subview depths
      
      ZStack {
        Model3D(named: "LargeRobot")
          .debugBorder3D(.red)
        Model3D(named: "BabyBot")
          .debugBorder3D(.red)
      }
      .debugBorder3D(.yellow)
    • 6:33 - ZStack with RealityView

      // ZStack composes subview depths
      
      ZStack {
        RealityView { ... }
          .debugBorder3D(.red)
        Model3D(named: "BabyBot")
          .debugBorder3D(.red)
      }
      .debugBorder3D(.yellow)
    • 6:57 - Layouts are 3D

      // HStack also composes subview depths
      
      HStack {
        Model3D(named: "LargeRobot")
          .debugBorder3D(.red)
        Model3D(named: "BabyBot")
          .debugBorder3D(.red)
      }
      .debugBorder3D(.yellow)
    • 7:50 - ResizableRobotView

      struct ResizableRobotView: View {
        let asset: Model3DAsset
      
        var body: some View {
          Model3D(asset: asset) { resolved in
            resolved
              .resizable()
          }
          .scaledToFit3D()
        }
      }
    • 8:11 - Robot Profile 1

      //`Layout` types back align views by default
      
      struct RobotProfile: View {
        let robot: Robot
      
        var body: some View {
          VStack {
            ResizableRobotView(asset: robot.model3DAsset)
            RobotNameCard(robot: robot)
          }
          .frame(width: 300)
        }
      }
    • 8:38 - Customizing Vertical Alignment

      // Customizing vertical alignment
      
      HStack(alignment: .bottom) {
        Image("RobotHead")
          .border(.red)
        Color.blue
          .frame(width: 100, height: 100)
          .border(.red)
      }
      .border(.yellow)
    • 8:52 - Customizing Depth Alignment

      // Customizing depth alignments
      
      struct RobotProfile: View {
        let robot: Robot
      
        var body: some View {
          VStackLayout().depthAlignment(.front) {
            ResizableRobotView(asset: robot.model3DAsset)
            RobotNameCard(robot: robot)
          }
          .frame(width: 300)
        }
      }
    • 9:45 - Robot Favorite Row

      struct FavoriteRobotsRow: View {
        let robots: [Robot]
      
        var body: some View {
          HStack {
            RobotProfile(robot: robots[2])
            RobotProfile(robot: robots[0])
            RobotProfile(robot: robots[1])
          }
        }
      }
    • 10:27 - Custom Depth Alignment ID

      // Defining a custom depth alignment guide
      
      struct DepthPodiumAlignment: DepthAlignmentID {
        static func defaultValue(in context: ViewDimensions3D) -> CGFloat {
          context[.front]
        }
      }
      
      extension DepthAlignment {
        static let depthPodium = DepthAlignment(DepthPodiumAlignment.self)
      }
    • 10:51 - Customizing Depth Alignment Guides

      // Views can customize their alignment guides
      
      struct FavoritesRow: View {
        let robots: [Robot]
      
        var body: some View {
          HStackLayout().depthAlignment(.depthPodium) {
              RobotProfile(robot: robots[2])
              RobotProfile(robot: robots[0])
                .alignmentGuide(.depthPodium) {
                  $0[DepthAlignment.back]
                }
              RobotProfile(robot: robots[1])
            		.alignmentGuide(.depthPodium) {
                  $0[DepthAlignment.center]
                }
          }
        }
      }
    • 12:00 - Rotation3DEffect

      // Rotate views using visual effects
      
      Model3D(named: "ToyRocket")
        .rotation3DEffect(.degrees(45), axis: .z)
    • 12:10 - Rotation3DLayout

      // Rotate using any axis or angle
      
      HStackLayout().depthAlignment(.front) {
        RocketDetailsCard()
        Model3D(named: "ToyRocket")
        	.rotation3DLayout(.degrees(isRotated ? 45 : 0), axis: .z)
      }
    • 14:42 - Pet Radial Layout

      // Custom radial Layout
      
      struct PetRadialLayout: View {
        let pets: [Pet]
      
        var body: some View {
          MyRadialLayout {
            ForEach(pets) { pet in
              PetImage(pet: pet)
            }
          }
        }
      }
    • 14:56 - Rotated Robot Carousel

      struct RobotCarousel: View {
        let robots: [Robot]
      
        var body: some View {
      		VStack {
            Spacer()
            MyRadialLayout {
              ForEach(robots) { robot in
                ResizableRobotView(asset: robot.model3DAsset)
                	.rotation3DLayout(.degrees(-90), axis: .x)
              }
            }
            .rotation3DLayout(.degrees(90), axis: .x)
        }
      }
    • 17:00 - Spatial Container

      // Aligning views in 3D space
      
      SpatialContainer(alignment: .topTrailingBack) {
        LargeBox()
        MediumBox()
        SmallBox()
      }
    • 17:35 - Spatial Overlay

      // Aligning overlayed content
      
      LargeBox()
        .spatialOverlay(alignment: .bottomLeadingFront) {
          SmallBox()
        }
    • 17:47 - Selection Ring Spatial Overlay

      struct RobotCarouselItem: View {
        let robot: Robot
        let isSelected: Bool
      
        var body: some View {
          ResizableRobotView(asset: robot.model3DAsset)
      			.spatialOverlay(alignment; .bottom) {
              if isSelected {
                ResizableSelectionRingModel()
              }
        }
      }
    • 18:32 - DebugBorder3D

      extension View {
        func debugBorder3D(_ color: Color) -> some View {
          spatialOverlay {
      			ZStack {
      				Color.clear.border(color, width: 4)
              ZStack {
                Color.clear.border(color, width: 4)
                Spacer()
                Color.clear.border(color, width: 4)
              }
              .rotation3DLayout(.degrees(90), axis: .y)
      				Color.clear.border(color, width: 4)
            }
          }
        }
    • 0:00 - Introducción
    • Las nuevas capacidades de diseño 3D de SwiftUI en visionOS 26 le permiten crear apps 3D utilizando la sintaxis declarativa de SwiftUI. Estas capacidades se basan en conceptos de diseño 2D existentes y brindan soporte integrado para animaciones, cambio de tamaño y gestión de estados. La app de ejemplo BOT-anist demuestra cómo las personas pueden personalizar y catalogar robots en un jardín virtual. Si nunca trabajaste con diseños de SwiftUI, consulta “Crea diseños personalizados con SwiftUI” y “Compone diseños personalizados con SwiftUI” antes de profundizar en este contenido.

    • 2:47 - Vistas 3D
    • En SwiftUI, el sistema de diseño calcula el ancho, la altura y las posiciones X e Y para cada vista de una app. Algunas vistas tienen marcos fijos, mientras que otras tienen marcos flexibles que llenan el espacio disponible proporcionado por el padre. En visionOS, este concepto se extiende a tres dimensiones. Cada vista tiene una profundidad y una posición Z además de ancho y alto. El sistema de diseño se comporta de manera similar al 2D pero se aplica al espacio 3D. Las vistas pueden tener profundidad fija, flexible o cero. GeometryReader3D y Model3D con el modificador 'redimensionable' puede ocupar toda la profundidad disponible. El nuevo modificador 'scaledToFit3D' ayuda a mantener las relaciones de aspecto mientras se cambia el tamaño. Las ventanas tienen una propuesta de profundidad de raíz fija, mientras que los volúmenes tienen una profundidad redimensionable. El contenido fuera de esta profundidad puede recortarse por el sistema. ZStack compone profundidades como VStack compone alturas y los tipos de diseño existentes como HStack y VStack son automáticamente 3D en visionOS, aplicando comportamientos predeterminados sensatos para la profundidad, como alinear los elementos a lo largo de sus partes posteriores.

    • 7:18 - Alineaciones de profundidad
    • Las alineaciones de profundidad son una nueva característica de visionOS 26 que puede utilizar para personalizar las vistas de posicionamiento en el espacio 3D, de forma similar a cómo funcionan las alineaciones verticales y horizontales en 2D. Este enfoque es especialmente útil al crear ventanas volumétricas o visualizar modelos 3D. El ejemplo demuestra cómo utilizar la alineación de profundidad para mejorar la legibilidad de una vista del perfil de un robot. Al aplicar el modificador de alineación de profundidad '.front' a la tarjeta con el nombre del robot, este se mueve al frente, lo que hace que sea más fácil de ver. Para escenarios más complejos, puede crear alineaciones de profundidad personalizadas. El ejemplo muestra cómo definir un 'DepthPodiumAlignment' personalizado para escalonar tres vistas de perfil de robot en profundidad, con el robot favorito más cercano al espectador, creando una sensación de prominencia.

    • 11:41 - Diseño de rotación
    • visionOS 26 presenta el nuevo modificador 'rotation3DLayout' para abordar las limitaciones del modificador 'rotation3DEffect' existente. El modificador 'rotation3DEffect' solo aplica rotaciones visuales sin afectar el sistema de diseño, lo que causa problemas al rotar vistas dentro de contenedores como HStacks. 'rotation3DEffect' sigue siendo útil cuando quieres animar una vista sin afectar los cuadros de los demás. El modificador 'rotation3DLayout' modifica el marco de una vista rotada dentro del sistema de diseño, lo que permite ajustes adecuados de tamaño y ubicación, lo que permite diseños 3D más complejos. Por ejemplo, puedes usarlo para crear un carrusel de robot orientado horizontalmente girando un RadialLayout personalizado 90 grados a lo largo del eje X. Cada robot del carrusel gira en sentido contrario para quedar en posición vertical. Se pueden aplicar ajustes adicionales, como el uso de un VStack con un espaciador, para colocar el carrusel al ras de la base del volumen, creando una IU 3D pulida y visualmente atractiva.

    • 16:28 - Contenedores espaciales
    • 'SpatialContainer' y 'SpatialOverlay' son nuevas herramientas en SwiftUI para diseño 3D. SpatialContainer permite anidar múltiples vistas en el espacio 3D con opciones de alineación, mientras que SpatialOverlay superpone una sola vista sobre otra. El ejemplo utiliza SpatialOverlay para crear un anillo de selección para robots en un carrusel, alineándolo con la parte inferior del robot. El modificador de ejemplo 'debugBorder3D' se demuestra como una extensión de View, utilizando 'SpatialOverlay', ZStacks y 'rotation3DLayout' para agregar bordes 3D a cualquier Model3D con fines de depuración.

    • 19:22 - Próximos pasos
    • SwiftUI ahora permite el desarrollo de apps 3D utilizando modificadores 2D familiares y nuevas API 3D. Puedes combinar SwiftUI con RealityKit para obtener una funcionalidad mejorada. Encuentra ejemplos de esta integración en "Better Together: SwiftUI y RealityKit".

Developer Footer

  • Videos
  • WWDC25
  • Conoce el diseño espacial de SwiftUI
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines