Construção de um Layout de Fluxo
Distribua itens em várias linhas dinamicamente.
Construção de um Layout de Fluxo é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 3 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.
O Que É um Layout de Fluxo
Um layout de fluxo posiciona os itens da esquerda para a direita, quebrando para uma nova linha quando o próximo item ultrapassaria a largura disponível — como chips de tags ou a quebra de palavras.
O Plano
Vamos calcular as quebras de linha em um auxiliar compartilhado, retornar a altura total de sizeThatFits e reutilizar o mesmo cálculo em placeSubviews. Compartilhar a lógica mantém os dois métodos consistentes.
Modelando um Posicionamento
Uma pequena estrutura registra onde cada subvisualização deve ficar. Calcular todos os posicionamentos antecipadamente torna os dois métodos do protocolo triviais.
struct Placement {
let index: Int
let point: CGPoint
let size: CGSize
}O Algoritmo de Quebra de Linha
Percorra as subvisualizações acompanhando o x atual. Se um elemento filho ultrapassar a largura máxima, redefina x e desça pela altura da linha mais o espaçamento.
func layout(_ subviews: Subviews, maxWidth: CGFloat) -> (placements: [Placement], height: CGFloat) {
var placements: [Placement] = []
var x: CGFloat = 0, y: CGFloat = 0, rowHeight: CGFloat = 0
let spacing: CGFloat = 8
for (i, s) in subviews.enumerated() {
let size = s.sizeThatFits(.unspecified)
if x + size.width > maxWidth, x > 0 {
x = 0; y += rowHeight + spacing; rowHeight = 0
}
placements.append(Placement(index: i, point: CGPoint(x: x, y: y), size: size))
x += size.width + spacing
rowHeight = max(rowHeight, size.height)
}
return (placements, y + rowHeight)
}Implementando sizeThatFits
sizeThatFits executa o algoritmo usando a largura proposta e retorna a largura da proposta pela altura total calculada.
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxWidth = proposal.width ?? .infinity
let result = layout(subviews, maxWidth: maxWidth)
return CGSize(width: maxWidth == .infinity ? result.placements.map { $0.point.x + $0.size.width }.max() ?? 0 : maxWidth,
height: result.height)
}Implementando placeSubviews
placeSubviews executa o mesmo algoritmo, depois desloca cada posicionamento por bounds.origin e chama place.
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let result = layout(subviews, maxWidth: bounds.width)
for p in result.placements {
let pt = CGPoint(x: bounds.minX + p.point.x, y: bounds.minY + p.point.y)
subviews[p.index].place(at: pt, anchor: .topLeading,
proposal: ProposedViewSize(p.size))
}
}O Tipo FlowLayout Completo
Combinando as partes, obtemos um layout de fluxo completo e reutilizável. O auxiliar compartilhado layout garante que o tamanho e o posicionamento estejam de acordo.
struct FlowLayout: Layout {
var spacing: CGFloat = 8
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let r = layout(subviews, maxWidth: proposal.width ?? .infinity)
return CGSize(width: proposal.width ?? 0, height: r.height)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let r = layout(subviews, maxWidth: bounds.width)
for p in r.placements {
subviews[p.index].place(at: CGPoint(x: bounds.minX + p.point.x, y: bounds.minY + p.point.y),
anchor: .topLeading, proposal: ProposedViewSize(p.size))
}
}
}Usando o Layout de Fluxo
Adicione-o como faria com qualquer contêiner. As tags quebram automaticamente à medida que a largura diminui.
var body: some View {
FlowLayout {
ForEach(tags, id: \.self) { tag in
Text(tag)
.padding(8)
.background(.blue.opacity(0.2))
.clipShape(Capsule())
}
}
}Lidando com o Primeiro Item de Cada Linha
A condição x > 0 impede a quebra antes do primeiro item de uma linha. Sem ela, um item mais largo que o contêiner poderia entrar em um loop infinito ou ser deslocado desnecessariamente para uma linha vazia.
if x + size.width > maxWidth, x > 0 {
// wrap only if the row already has content
}Escolhas de Espaçamento
Aqui, o spacing é uma propriedade armazenada com um valor padrão. Em produção, leia a preferência de spacing de cada subvisualização para respeitar as métricas do sistema em vez de usar uma constante fixa.
var spacing: CGFloat = 8 // configurable per instanceTestando Casos Extremos
Teste com zero itens, um item enorme e muitos itens pequenos. Um layout de fluxo correto informa altura zero para conteúdo vazio e nunca recorta um único elemento filho grande demais.
Verificação Rápida: Layout de Fluxo
Teste sua compreensão do algoritmo de quebra de linha.
Recapitulação: Criando um Layout de Fluxo
Um layout de fluxo quebra os itens acompanhando o x acumulado e redefinindo-o para uma nova linha quando o próximo elemento filho ultrapassaria os limites. Um auxiliar compartilhado calcula todos os posicionamentos e a altura total para que sizeThatFits e placeSubviews permaneçam consistentes.
Desloque os posicionamentos por bounds.origin, trate o primeiro item de cada linha e teste os casos vazio, grande demais e com muitos itens. O resultado é um contêiner reutilizável com quebra de linha.
Perguntas Frequentes
A aula “Construção de um Layout de Fluxo” é grátis?
Sim — o texto completo de “Construção de um Layout de Fluxo” é 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 “Construção de um Layout de Fluxo”?
Distribua itens em várias linhas dinamicamente. 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 3 de 4.
Quanto tempo leva a aula “Construção de um Layout de Fluxo”?
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
- Noções Básicas do Protocolo Layout
- Medição de Subviews
- Construção de um Layout de Fluxo
- Cache de Layout e Desempenho