0Pricing
Swift Academy · Aula

Noções Básicas do Protocolo Layout

Implemente sizeThatFits e placeSubviews.

Noções Básicas do Protocolo Layout é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Swift Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Swift Academy inclui 4 aulas no total.

Por que uma Disposição Personalizada?

O SwiftUI oferece HStack, VStack e ZStack, mas às vezes você precisa de uma lógica de disposição que elas não conseguem expressar — menus radiais, disposições em fluxo e grades assimétricas.

O protocolo Layout permite escrever essa lógica e ainda compor com visualizações SwiftUI comuns.

O Protocolo Layout

Layout exige dois métodos: sizeThatFits (qual é o meu tamanho?) e placeSubviews (onde cada filho deve ficar?).

Você torna um tipo de valor conforme ao protocolo e o usa como qualquer pilha integrada.

struct MyLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize,
                      subviews: Subviews,
                      cache: inout ()) -> CGSize { .zero }
    func placeSubviews(in bounds: CGRect,
                       proposal: ProposedViewSize,
                       subviews: Subviews,
                       cache: inout ()) { }
}

Usando uma Disposição Personalizada

Um valor de Layout atua como um contêiner. Você passa as visualizações filhas em sua função de fechamento final, exatamente como em uma pilha.

var body: some View {
    MyLayout {
        Text("One")
        Text("Two")
        Text("Three")
    }
}

ProposedViewSize

O pai propõe um tamanho à sua disposição por meio de ProposedViewSize. Seus valores de width e height são opcionais: nil significa "não especificado; escolha seu tamanho ideal".

Os valores especiais .zero, .infinity e .unspecified consultam os tamanhos mínimo, máximo e ideal.

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    let width = proposal.width ?? 0
    return CGSize(width: width, height: 44)
}

sizeThatFits em Detalhes

sizeThatFits retorna o tamanho desejado pela sua disposição para uma determinada proposta. O SwiftUI pode chamá-lo várias vezes com propostas diferentes para entender sua flexibilidade.

func sizeThatFits(proposal: ProposedViewSize,
                  subviews: Subviews,
                  cache: inout ()) -> CGSize {
    // Sum child ideal sizes for a simple horizontal stack
    let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
    let w = sizes.reduce(0) { $0 + $1.width }
    let h = sizes.map(\.height).max() ?? 0
    return CGSize(width: w, height: h)
}

A Coleção de Subvisualizações

Subviews é uma coleção de representantes de cada filho. Cada representante responde a sizeThatFits e expõe prioridades de disposição e valores personalizados.

Você nunca vê as visualizações reais — apenas esses representantes de medição.

for subview in subviews {
    let size = subview.sizeThatFits(.unspecified)
    print(size)
}

placeSubviews

placeSubviews atribui a cada filho uma posição dentro do retângulo bounds fornecido.

Chame place(at:anchor:proposal:) em cada representante de subvisualização.

func placeSubviews(in bounds: CGRect,
                   proposal: ProposedViewSize,
                   subviews: Subviews,
                   cache: inout ()) {
    var x = bounds.minX
    for subview in subviews {
        let size = subview.sizeThatFits(.unspecified)
        subview.place(at: CGPoint(x: x, y: bounds.midY),
                      anchor: .leading,
                      proposal: .unspecified)
        x += size.width
    }
}

Âncoras ao Posicionar

O parâmetro anchor indica qual ponto do filho ficará sobre a posição fornecida. .topLeading posiciona pelo canto superior esquerdo; .center centraliza o filho sobre o ponto.

subview.place(at: CGPoint(x: 0, y: 0),
              anchor: .topLeading,
              proposal: .unspecified)

bounds Nem Sempre Começa na Origem

O retângulo bounds pode não começar em (0,0). Sempre posicione em relação a bounds.minX e bounds.minY, nunca em relação ao zero absoluto.

let startX = bounds.minX // not 0
let startY = bounds.minY

Uma Disposição Mínima com Espaçamento Uniforme

Juntando tudo, esta é uma disposição que organiza os filhos da esquerda para a direita, sem espaçamento. Os dois métodos permanecem consistentes: o tamanho informado corresponde ao posicionamento.

struct SimpleHStack: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
        return CGSize(width: sizes.reduce(0){ $0 + $1.width },
                      height: sizes.map(\.height).max() ?? 0)
    }
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        var x = bounds.minX
        for s in subviews {
            let size = s.sizeThatFits(.unspecified)
            s.place(at: CGPoint(x: x, y: bounds.minY), anchor: .topLeading, proposal: .unspecified)
            x += size.width
        }
    }
}

A Consistência é Sua Responsabilidade

O SwiftUI confia que seus dois métodos estejam de acordo. Se placeSubviews usar mais espaço do que o informado por sizeThatFits, os filhos poderão ser cortados ou se sobrepor.

Mantenha os cálculos geométricos compartilhados entre os dois métodos.

Verificação Rápida: Fundamentos de Layout

Teste sua compreensão do protocolo Layout.

Recapitulação: Fundamentos do Protocolo Layout

O protocolo Layout transforma a lógica de disposição personalizada em um contêiner reutilizável. sizeThatFits informa seu tamanho para um ProposedViewSize, e placeSubviews posiciona cada representante de filho dentro de bounds usando place(at:anchor:proposal:).

As propostas carregam dimensões opcionais, bounds pode estar deslocado da origem, e os dois métodos precisam permanecer geometricamente consistentes. A seguir, mediremos as subvisualizações em profundidade.

Perguntas Frequentes

A aula “Noções Básicas do Protocolo Layout” é grátis?

Sim — o texto completo de “Noções Básicas do Protocolo Layout” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Swift Academy, atualize para CoddyKit PRO. O curso de Swift Academy inclui 4 aulas no total.

O que vou aprender em “Noções Básicas do Protocolo Layout”?

Implemente sizeThatFits e placeSubviews. Você pratica Swift Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Swift Academy?

Nenhuma experiência prévia é necessária. Swift Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Noções Básicas do Protocolo Layout”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Swift Academy?

Sim. Cada aula de Swift Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Noções Básicas do Protocolo Layout
  2. Medição de Subviews
  3. Construção de um Layout de Fluxo
  4. Cache de Layout e Desempenho
← Voltar para Swift Academy