0Pricing
Swift Academy · Lección

Crear un diseño de flujo

Distribuya los elementos dinámicamente en varias líneas.

Crear un diseño de flujo es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué es un layout de flujo?

Un layout de flujo coloca los elementos de izquierda a derecha y los ajusta en una fila nueva cuando el siguiente elemento desbordaría el ancho disponible, como ocurre con las etiquetas o el ajuste de palabras.

El plan

Calcularemos los saltos de fila en un helper compartido, devolveremos la altura total desde sizeThatFits y reutilizaremos el mismo cálculo en placeSubviews. Compartir la lógica mantiene la coherencia entre ambos métodos.

Modelar una colocación

Una estructura pequeña registra dónde se coloca cada subvista. Calcular todas las colocaciones por adelantado simplifica ambos métodos del protocolo.

struct Placement {
    let index: Int
    let point: CGPoint
    let size: CGSize
}

El algoritmo de ajuste

Recorra las subvistas y realice un seguimiento de la x actual. Si una vista secundaria superaría el ancho máximo, restablezca x y baje en una cantidad igual a la altura de la fila más el espaciado.

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)
}

Implementar sizeThatFits

sizeThatFits ejecuta el algoritmo con el ancho propuesto y devuelve el ancho de la propuesta junto con la 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)
}

Implementar placeSubviews

placeSubviews ejecuta el mismo algoritmo, desplaza cada colocación según bounds.origin y llama a 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))
    }
}

El tipo FlowLayout completo

Al combinar las piezas se obtiene un layout de flujo completo y reutilizable. El helper compartido layout garantiza que el tamaño y la colocación coincidan.

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))
        }
    }
}

Usar el layout de flujo

Incorpórelo como cualquier contenedor. Las etiquetas se ajustan automáticamente a medida que se reduce el ancho.

var body: some View {
    FlowLayout {
        ForEach(tags, id: \.self) { tag in
            Text(tag)
                .padding(8)
                .background(.blue.opacity(0.2))
                .clipShape(Capsule())
        }
    }
}

Gestionar el primer elemento de cada fila

La condición x > 0 evita ajustar la primera fila antes de colocar su primer elemento. Sin ella, un elemento más ancho que el contenedor podría entrar en un bucle infinito o pasar innecesariamente a una fila vacía.

if x + size.width > maxWidth, x > 0 {
    // wrap only if the row already has content
}

Opciones de espaciado

Aquí el espaciado es una propiedad almacenada con un valor predeterminado. En producción, lea la preferencia de spacing de cada subvista para respetar las métricas del sistema en lugar de usar una constante fija.

var spacing: CGFloat = 8 // configurable per instance

Probar casos límite

Pruebe con cero elementos, un elemento enorme y muchos elementos pequeños. Un layout de flujo correcto indica una altura de cero para el contenido vacío y nunca recorta una única vista secundaria que sea demasiado grande.

Comprobación rápida: layout de flujo

Compruebe su comprensión del algoritmo de ajuste.

Resumen: crear un layout de flujo

Un layout de flujo ajusta los elementos realizando un seguimiento de la x acumulada y restableciéndola en una fila nueva cuando la siguiente vista secundaria desbordaría el espacio. Un helper compartido calcula todas las colocaciones y la altura total para que sizeThatFits y placeSubviews sean coherentes.

Desplace las colocaciones según bounds.origin, gestione el primer elemento de cada fila y pruebe los casos de contenido vacío, elementos demasiado grandes y muchos elementos. El resultado es un contenedor reutilizable con ajuste de elementos.

Preguntas frecuentes

¿La lección «Crear un diseño de flujo» es gratis?

Sí — el texto completo de «Crear un diseño de flujo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Crear un diseño de flujo»?

Distribuya los elementos dinámicamente en varias líneas. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Crear un diseño de flujo»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Fundamentos del protocolo Layout
  2. Medición de subvistas
  3. Crear un diseño de flujo
  4. Caché y rendimiento del diseño
← Volver a Swift Academy