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

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Tópicos
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Resumo
  • Transcrição
  • Código
  • Conheça o layout espacial do SwiftUI

    Explore novas ferramentas para criar experiências espaciais usando o SwiftUI. Aprenda os fundamentos das visualizações 3D do SwiftUI no visionOS, personalize os layouts existentes com alinhamentos de profundidade e use modificadores para girar e posicionar as visualizações no espaço. Saiba como usar contêineres espaciais para alinhar visualizações no mesmo espaço 3D e criar apps imersivos e interessantes.

    Capítulos

    • 0:00 - Introdução
    • 2:47 - Visualizações 3D
    • 7:18 - Alinhamentos de profundidade
    • 11:41 - Layout de rotação
    • 16:28 - SpatialContainer
    • 19:22 - Próximas etapas

    Recursos

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

    Vídeos relacionados

    WWDC25

    • Melhor juntos: SwiftUI e RealityKit

    WWDC22

    • Compose custom layouts with SwiftUI

    WWDC19

    • Building Custom Views with SwiftUI
  • Buscar neste vídeo...

    Olá! Esta é a sessão “Conhecer o layout espacial da SwiftUI”. Meu nome é Trevor. Sou engineer na equipe SwiftUI. Hoje, vamos ver técnicas para criar experiências espaciais com a SwiftUI. Tenho testado os novos recursos de layout espacial da SwiftUI expandindo um app que adoro, o BOT-anist.

    O app permite personalizar robôs divertidos com vários elementos essenciais, cores e materiais. Você pode usar os bots recém-criados para cuidar do seu próprio jardim virtual. Adoro construir esses robôs, e tenho trabalhado em novas visualizações para catalogar as criações.

    Agora, você pode personalizar os robôs, salvá-los e colecionar vários deles.

    Vou mostrar algumas novas cenas 3D para explorar com os robôs. Criei todas essas experiências com a SwiftUI.

    Se você já criou experiências 3D no visionOS, talvez tenha usado o RealityKit.

    O RealityKit é um ótimo framework para criar apps 3D, principalmente com comportamentos complexos, como simulações de física.

    Se estiver migrando da SwiftUI, recomendo criar a sintaxe declarativa que você já conhece. E talvez não precise de todos os recursos do RealityKit em todo o app. No visionOS 26, você pode usar as ferramentas e ideias de layout 2D da SwiftUI para criar apps 3D.

    Ao usar o layout da SwiftUI, seu app é compatível com animações, redimensionamento e gerenciamento de estado, ou seja, quando retiro um bot do carrossel, a SwiftUI pode animar as posições e tamanhos dos outros robôs para redistribuir o espaço.

    E o redimensionamento de volume redimensiona o carrossel e cada robô dentro dele. Vamos ver as novas ferramentas que usei para a organização dos autômatos.

    As extensões 3D do sistema de layout da SwiftUI se baseiam em conceitos de layout 2D existentes.

    Se nunca trabalhou com layouts da SwiftUI, confira “Criar views personalizadas com a SwiftUI” e “Criar layouts personalizados com a SwiftUI” antes de continuar. Vamos abordar os conceitos básicos das visualizações 3D da SwiftUI no visionOS, como personalizar layouts com ajustes de profundidade, rotation3DLayout, um novo modificador para girar visualizações no layout, e SpatialContainer e spatialOverlay, uma forma de alinhar visualizações no espaço 3D.

    Vamos falar sobre visualizações e o sistema de layout.

    Em cada visualização, a SwiftUI calcula uma largura, altura e posição X e Y.

    Algumas visualizações, como imagem não redimensionável, têm quadro fixo de acordo com o tamanho do ativo.

    Algumas visualizações, como esta cor, têm quadros flexíveis e ocupam todo o espaço que é fornecido por um item principal.

    Os layouts compõem os itens secundários em um quadro final. O quadro deste VStack, em amarelo, é determinado pelo espaço disponível para ele e pelos itens secundários que contém. Sua altura é a soma das duas imagens dentro dele. O visionOS age da mesma forma, mas as visualizações são 3D. O sistema de layout tem os mesmos comportamentos, só que aplicado a três dimensões, e não duas.

    Ou seja, para cada visualização, além de largura e altura, a SwiftUI também calcula a profundidade e a posição Z. Costumo usar o modificador de borda para visualizar quadros 2D no iOS.

    Aqui, criei um modificador debugBorder3D para visualizar quadros 3D no visionOS. Vou mostrar como criei esse modificador no final deste vídeo usando algumas das APIs sobre as quais você aprenderá.

    O debugBorder3D mostra que o Model3D se comporta semelhante a imagem, mas em três dimensões em vez de duas, com largura, altura e profundidade fixas. As visualizações são 3D, algumas têm profundidade 0.

    Muitas das que usa para criar experiências planares, como Image, Color e Text, têm profundidade 0, se comportando exatamente como no iOS.

    Algumas têm profundidade flexível, da mesma forma que Color ocupa toda a largura e altura disponíveis propostas por padrão. No visionOS, certas visualizações, como RealityView, ocupam toda a profundidade proposta por padrão.

    GeometryReader3D tem o mesmo comportamento de dimensionamento flexível, bem como Model3D com o modificador redimensionável aplicado, que esticou o robô para caber na largura da janela. A cara dele ficou muito longa nesta proporção. Quero voltar para as proporções originais enquanto o dimensiono ao espaço.

    Posso usar o modificador scaledToFit3D além do resizable(), para que o robô mantenha a proporção e possa dimensionar para cima ou para baixo para se ajustar à largura, altura e profundidade.

    Então, como surge essa profundidade? Assim como largura e altura, o conteúdo de Windows recebe uma proposta profundidade. Ao contrário da largura e altura, que podem ser redimensionáveis, a proposta de Windows é fixa. Se o conteúdo ultrapassar o valor, ele poderá ser cortado pelo sistema.

    Da mesma forma, um volume irá propor largura, altura e profundidade, mas a profundidade será redimensionável. Confira “Projetar para o visionOS” nas Human Interface Guidelines para saber quando usar um volume ou uma janela.

    Algumas visualizações alteram as propostas para visualizações contidas. Assim como o VStack compõe as alturas das subvisualizações o ZStack compõe profundidades. A profundidade do ZStack é a necessária para encaixar ambos os robôs empilhados frente a frente.

    Da mesma forma que o VStack pode propor alturas diferentes para subvisualizações com base no espaço disponível, número e tipo de itens secundários, o ZStack pode propor diferentes profundidades para os itens secundários com base nos mesmos fatores. Aqui, o RealityView empurra o robô para frente no ZStack, preenchendo toda a profundidade disponível.

    Os tipos de layout e pilhas existentes são 3D no visionOS e aplicarão comportamentos padrão para profundidade. Neste exemplo, o HStack usará uma proposta de profundidade do item principal e definirá a própria profundidade para se ajustar aos dois modelos nele.

    O HStack também alinha a aprte de trás desses dois robôs por padrão.

    É o alinhamento de profundidade. Ele é uma nova ferramenta para personalizar os tipos de layout da SwiftUI para acomodar melhor as visualizações 3D e a profundidade. Se você já trabalhou com alinhamentos verticais ou horizontais, eles vão parecer familiares. Quero construir uma janela volumétrica para exibir meus robôs favoritos com nome e descrição. Vamos atualizar o código do robô do Model3D para torná-lo mais reutilizável.

    Começo com o Model3D que é dimensionado para caber no espaço.

    Vou refatorá-lo para usar o novo tipo Model3DAsset, que permite pré-carregar o modelo do robô. Incluo tudo isso em uma nova ResizableRobotView, que posso usar em todo o app. Por enquanto, vou remover debugBorder3D.

    Agora vou criar um RobotProfile usando um VStack com ResizableRobotView, além de um RobotNameCard com detalhes sobre o bot.

    Mas há um problema.

    É difícil ler o cartão, pois está na parte de trás do VStack e se perde atrás do modelo de robô.

    Assim como configura no HStack para alinhar o conteúdo na borda central, superior ou inferior, defina o alinhamento da profundidade no visionOS.

    Por padrão, os tipos Stacks e Layout alinham a profundidade traseira. No visionOS 26, você pode personalizar DepthAlignments em todo tipo de layout.

    Vou atualizar o RobotProfile para usar VStackLayout.

    Assim, posso aplicar o modificador depthAlignment. Peço alinhamento .front aqui.

    Também pode usar as guias central ou traseira.

    Mas acho que frontal é melhor para tornar este cartão de nome legível.

    Agora, nunca vou esquecer o Zapper Ironheart e seu conhecimento avançado de fatos obscuros.

    Usar os alinhamentos padrão de profundidade frontal, traseira ou central é ótimo para uma dessas três configurações padrão. Mas e se você precisar de algo mais complexo do que isso?

    Estou criando um volume para mostrar meus três robôs favoritos com três visualizações do perfil dos robôs no HStack. Greg-gear Mendel é meu robô favorito, e quero destacá-lo mais que os outros dois.

    Quero criar um pódio de alinhamento: Quanto mais eu gostar de um robô, mais perto ficará de mim. O robô 1 é o mais próximo, seguido por 2 e 3.

    De cima para baixo, quero que fique assim: A parte de trás do primeiro robô está alinhada em profundidade com o centro do segundo e a frente do terceiro. Vou precisar de alinhamento de profundidade personalizado.

    Primeiro, vou definir uma nova estrutura que siga o protocolo DepthAlignmentID.

    Implemento o único requisito, que é o valor padrão para esse alinhamento.

    Uso o guia de alinhamento frontal como padrão para o DepthPodiumAlignment.

    Depois, defino uma constante estática no alinhamento de profundidade que usa o tipo DepthAlignmentID.

    Agora posso usar o guia depthPodium como um alinhamento de profundidade no HStack contendo cada robô.

    Isso alinhará a perte frontal de todos os robôs, com o valor padrão que acabamos de especificar para o guia.

    Agora vou personalizar o guia depthPodium no robô à direita para alinhar o centro de profundidade com este guia.

    Vou modificar o robô central para alinhar a traseira com depthPodium.

    O robô líder continuará usando o guia frontal como padrão para esse alinhamento.

    Veja como fica no simulador.

    Com os bots espaçados em profundidade, ninguém duvida que o Greg-gear Mendel é o meu preferido.

    Os alinhamentos de profundidade são ótimos para ajustar a posição de profundidade em um layout. Mas e se você quiser criar algo pensando ainda mais na profundidade? O layout de rotação é ótimo para casos de uso 3D mais avançados. Talvez você conheça o modificador rotation3DEffect, que aplica um efeito visual para girar uma visualizações em torno de um eixo.

    Ele é ótimo para rotações básicas.

    Se colocarmos o modelo em um HStack com um cartão de descrição e girarmos o foguete 90º no eixo Z, ele colide com o cartão e ultrapassa o volume.

    Se aplicarmos wireframes de depuração antes e depois do efeito, fica mais fácil entender o que está acontecendo. O wireframe vermelho sólido é girado pelo efeito, mas o azul tracejado mostra o ponto no qual o sistema de layout entende a geometria do foguete. O HStack dimensiona e posiciona o conteúdo em relação ao quadro azul. Esses não se alinham. Isso ocorre porque os efeitos não afetam o layout. Ou seja, o HStack não entende a geometria girada do foguete ao usar o rotation3DEffect.

    Isso funciona para todos os efeitos visuais, como scaleEffect e offsets.

    Em todos os casos, o sistema de layout não ajustará o tamanho ou o posicionamento segundo os modificadores. Isso é ótimo quando você quer animar uma visualização sem afetar os quadros de outras ao redor.

    Mas e se você fizer isso? Como corrigir esse foguete rotacionado?

    Boas notícias. No visionOS 26, lançamos um novo modificador rotation3DLayout, que modifica o quadro de uma visualização girada no sistema de layout. Quando aplico no modelo de foguete, o HStack pode ajustar o tamanho e posicionamento para dar espaço ao foguete e ao cartão de detalhes.

    rotation3DLayout permite rotações em qualquer ângulo e eixo, ou seja, posso girar meu foguete a 45º para parecer que está decolando para o espaço.

    Aplico um wireframe de depuração antes e depois do rotation3DLayout. Isso mostra o quadro rotacionado em vermelho. O wireframe azul mostra o quadro da visualização modificada no sistema de layout. O eixo da caixa delimitadora azul está alinhado ao item principal e se ajusta ao quadro rotacionado vermelho.

    Agora vamos ver como podemos usar o rotation3DLayout para criar o carrossel de robôs que mostrei no início deste vídeo.

    Vou usar o RadialLayout de “Criar layouts personalizados com a SwiftUI”.

    Esse layout posiciona as visualizações em um círculo com a circunferência definida pela largura e altura.

    MyRadialLayout foi escrito para posicionar visualizações 2D no iOS, mas funciona bem no visionOS.

    Mesmo com modelos 3D de robôs no lugar de imagens 2D, podemos usar ForEach para posicionar os Model3Ds redimensionáveis no layout personalizado.

    Ficou bom, mas a experiência ainda está na vertical. Quero que os robôs fiquem na horizontal no volume.

    Aplicarei rotation3DLayout ao layout radial girando a visualização 90º ao longo do eixo X. O que antes era a altura do carrossel definirá a profundidade da visualização rotacionada no sistema. Meu carrossel está na orientação correta, mas os robôs estão deitados.

    Podemos erguê-los girando cada robô dentro de ForEach usando um segundo rotation3DEffect de -90º ao longo do eixo X. Esses dorminhocos estão agora de pé. Tem só mais uma coisa a corrigir. O carrossel está alinhado ao centro na altura do volume. Quero que o carrossel ficasse nivelado com a placa de base do volume.

    É mais fácil notar isso com debugBorder3D aplicado a todo o carrossel.

    Posso usar a mesma estratégia que para um layout 2D. Quero empurrar o carrossel para baixo no VStack com um espaçador acima. Meus robôs estão perfeitos na parte inferior do volume agora. Vamos falar sobre mais duas ferramentas no grupo de utilitários de layout 3D, SpatialContainer e spatialOverlay. Tem mais um recurso que quero adicionar ao carrossel de robôs. Tocar em um robô deve selecioná-lo, mostrando um menu de controles e um anel na parte inferior do modelo, indicando a seleção. Esse anel é representado como um Model3D. O anel deve preencher o mesmo espaço 3D que o robô. Não quero que empilhem em um eixo. Preciso de uma ferramenta que coloque os modelos no mesmo espaço 3D.

    Com a nova API SpatialContainer, é possível colocar várias visualizações no mesmo espaço 3D como várias matrioscas.

    Você pode aplicar alinhamento tridimensional a todas as visualizações. Aqui alinhamos os itens secundários de acordo com o guia bottomFront.

    E aqui, de acordo com o guia topTrailingBack.

    spatialOverlay é uma ferramenta semelhante, que permite sobrepor uma visualização no mesmo espaço 3D.

    Semelhante ao SpatialContainer, ele permite alinhamentos 3D.

    Só tenho duas visualizações para alinhar: o robô e o anel de seleção. Só estou preocupado com a geometria do robô. Já redimensionei meu anel ao tamanho do robô. Então vou usar spatialOverlay para implementar os visuais selecionados.

    Vou adicionar um modificador spatialOverlay ao modelo. E, se marcado como selecionado, coloque a visualização do anel como conteúdo. Vamos usar um alinhamento inferior para alinhar a parte inferior do anel com a do nosso robô.

    Nosso carrossel de robôs está ótimo. E podemos melhorar ainda mais com as APIs componíveis da SwiftUI.

    Vamos recapitular tudo o que aprendemos implementando debugBorder3D.

    Aqui está o modificador que mostrei aplicado a um Model3D.

    Defino um método debugBorder3D como extensão em View. Aplico um spatialOverlay para renderizar a borda no mesmo espaço 3D da visualização.

    Coloco um ZStack dentro com uma borda 2D, um espaçador e outra borda 2D.

    Aplico um rotation3DLayout em todo o ZStack para colocar bordas nas partes frontal e direita da visualização.

    Coloco este ZStack dentro de outro com bordas 2D para a frente e a traseira. Com isso, temos bordas em todas as pontas.

    Adoro poder usar esses modificadores 2D da SwiftUI com as novas APIs 3D para fazer algo completamente novo.

    Existem equivalentes 3D para muitas ferramentas e modificadores de layout que você já conhece do contexto 2D. Confira a documentação para obter mais dessas APIs.

    A SwiftUI é uma ótima ferramenta para criar apps 3D, mas em muitos casos você ainda vai usar o RealityKit, talvez misturando os dois no mesmo app.

    Agora que o conteúdo da SwiftUI está em 3D, talvez ele precise interagir com código do RealityKit. Meus amigos Maks e Amanda criaram adições incríveis ao BOT-anist usando ambos os frameworks juntos. Confira “Melhor juntos: SwiftUI e RealityKit” para saber mais. Estou ansioso esperar ver como seu app vai ficar em 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 - Introdução
    • Os novos recursos de layout 3D da SwiftUI no visionOS 26 permitem criar apps 3D usando a sintaxe declarativa da SwiftUI. Esses recursos se baseiam em conceitos de layout 2D existentes e têm compatibilidade integrada com animações, redimensionamento e gerenciamento de estado. O exemplo do BOT-anist demonstra como as pessoas podem personalizar e catalogar robôs em um jardim virtual. Se você não conhece os layouts da SwiftUI, confira “Criar views personalizadas com a SwiftUI” e “Criar layouts personalizados com a SwiftUI” antes de avançar neste conteúdo.

    • 2:47 - Visualizações 3D
    • Na SwiftUI, o sistema de layout calcula as posições de largura, altura, X e Y para cada visualização em um app. Alguns modos de visualização têm quadros fixos, e outros têm quadros flexíveis que ocupam o espaço disponível fornecido pelo item principal. No visionOS, esse conceito se estende a três dimensões. Cada visualização agora tem profundidade e posição Z, além de largura e altura. O layout se comporta de forma semelhante ao 2D, mas se aplica ao espaço 3D. As visualizações podem ter profundidade fixa, flexível ou zero. Usar o GeometryReader3D e o Model3D com o modificador resizable podem ocupar toda a profundidade. O novo modificador scaledToFit3D ajuda a manter as proporções durante o redimensionamento. As janelas têm uma proposta de profundidade raiz fixa, e os volumes têm profundidade redimensionável. O conteúdo fora dessa profundidade pode ser cortado pelo sistema. O ZStack compõe profundidades e o VStack compõe alturas, e os tipos de layout existentes, como HStack e VStack, já são 3D no visionOS, aplicando comportamentos padrão de profundidade, como alinhar os elementos pela parte de trás.

    • 7:18 - Alinhamentos de profundidade
    • Os alinhamentos de profundidade são um novo recurso no visionOS 26 e permitem posicionar visualizações personalizadas no espaço 3D, semelhante a como os alinhamentos vertical e horizontal funcionam em 2D. Essa abordagem é útil ao criar janelas volumétricas ou exibir modelos 3D. O exemplo mostra como usar o alinhamento de profundidade para melhorar a legibilidade de uma visualização de perfil de robô. Ao aplicar o modificador de alinhamento .front ao cartão de nome do robô, ele é movido para frente, facilitando a visualização. Para cenários mais complexos, você pode criar alinhamentos personalizados. O exemplo mostra como definir um DepthPodiumAlignment personalizado para distribuir três visualizações de perfis de robôs, com o favorito mais próximo do espectador, criando destaque.

    • 11:41 - Layout de rotação
    • O visionOS 26 introduz o novo modificador rotation3DLayout para resolver as limitações do modificador rotation3DEffect existente. O modificador rotation3DEffect aplica apenas rotações visuais sem afetar o sistema de layout, causando problemas ao girar visualizações dentro de contêineres como HStacks. O rotation3DEffect ainda é útil quando você deseja animar uma visualização sem afetar os quadros de outras. O rotation3DLayout modifica o quadro de uma visualização girada no layout do sistema, possibilitando ajustes adequados de dimensionamento e posicionamento, o que permite criar layouts 3D mais complexos. Por exemplo, você pode usá-lo para criar um carrossel de robôs na horizontal girando um RadialLayout personalizado 90 graus no eixo X. Cada robô no carrossel é girado no sentido contrário para ficar em pé. Ajustes adicionais, como o uso do VStack com um espaçador, podem ser aplicados para posicionar o carrossel nivelado com a base do volume, criando uma interface 3D polida e bonita.

    • 16:28 - SpatialContainer
    • O SpatialContainer e o SpatialOverlay são novas ferramentas da SwiftUI para layout 3D. O SpatialContainer permite aninhar várias visualizações no espaço 3D com opções de alinhamento, e o SpatialOverlay sobrepõe uma visualização a outra. O exemplo usa o SpatialOverlay para criar um anel de seleção para robôs em um carrossel, alinhando-o à parte inferior do robô. O modificador debugBorder3D de exemplo é demonstrado como uma extensão da visualização, usando SpatialOverlay, ZStacks e rotation3DLayout para adicionar bordas 3D a qualquer Model3D para depuração.

    • 19:22 - Próximas etapas
    • A SwiftUI agora permite o desenvolvimento de apps 3D usando modificadores 2D conhecidos e novas APIs 3D. Você pode combinar a SwiftUI com o RealityKit para melhorar a funcionalidade. Confira exemplos na sessão “Melhor juntos: SwiftUI e RealityKit”.

Developer Footer

  • Vídeos
  • WWDC25
  • Conheça o layout espacial do 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