0Pricing
Swift Academy · Lección

Fundamentos del protocolo Layout

Implemente sizeThatFits y placeSubviews.

Fundamentos del protocolo Layout es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 1 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.

¿Por qué un layout personalizado?

SwiftUI incluye HStack, VStack y ZStack, pero a veces necesita una lógica de disposición que no pueden expresar: menús radiales, layouts fluidos o cuadrículas de tipo masonry.

El protocolo Layout le permite escribir esa lógica y seguir componiéndola con vistas normales de SwiftUI.

El protocolo Layout

Layout requiere dos métodos: sizeThatFits (¿qué tamaño tengo?) y placeSubviews (¿dónde va cada hijo?).

Adopta el protocolo en un tipo de valor y lo usa como cualquier stack integrado.

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

Usar un layout personalizado

Un valor Layout actúa como contenedor. Se le pasan las vistas hijas en su closure final, exactamente igual que a un stack.

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

ProposedViewSize

El padre propone un tamaño a su layout mediante ProposedViewSize. Sus valores width y height son opcionales: nil significa «sin especificar, elija su tamaño ideal».

Los valores especiales .zero, .infinity y .unspecified permiten consultar los tamaños 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 en detalle

sizeThatFits devuelve el tamaño que desea su layout dada una propuesta. SwiftUI puede llamarlo varias veces con propuestas diferentes para conocer su flexibilidad.

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

La colección Subviews

Subviews es una colección de proxies para cada hijo. Cada proxy responde a sizeThatFits y expone las prioridades de layout y los valores personalizados.

Nunca ve las vistas reales, sino únicamente estos proxies de medición.

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

placeSubviews

placeSubviews asigna a cada hijo una posición dentro del rectángulo bounds que se le proporciona.

Llame a place(at:anchor:proposal:) en cada proxy de subvista.

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

Anclajes al colocar vistas

El parámetro anchor indica qué punto del hijo se coloca en la posición proporcionada. .topLeading coloca la esquina superior izquierda; .center centra el hijo en ese punto.

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

Los bounds no siempre empiezan en el origen

El rectángulo bounds puede no comenzar en (0,0). Coloque siempre los elementos en relación con bounds.minX y bounds.minY, nunca con el cero absoluto.

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

Un layout mínimo con espaciado uniforme

Al combinarlo todo, este layout coloca los hijos de izquierda a derecha sin espaciado. Los dos métodos siguen siendo coherentes: el tamaño informado coincide con la colocación.

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

La coherencia depende de usted

SwiftUI confía en que sus dos métodos coincidan. Si placeSubviews utiliza más espacio del que informó sizeThatFits, los hijos pueden recortarse o superponerse.

Mantenga los cálculos geométricos compartidos entre ambos métodos.

Comprobación rápida: conceptos básicos de Layout

Ponga a prueba su dominio del protocolo Layout.

Repaso: conceptos básicos del protocolo Layout

El protocolo Layout convierte la lógica de disposición personalizada en un contenedor reutilizable. sizeThatFits informa de su tamaño para un ProposedViewSize, y placeSubviews coloca cada proxy de hijo dentro de bounds mediante place(at:anchor:proposal:).

Las propuestas contienen dimensiones opcionales, los bounds pueden estar desplazados respecto al origen y los dos métodos deben mantener la coherencia geométrica. A continuación mediremos las subvistas en profundidad.

Preguntas frecuentes

¿La lección «Fundamentos del protocolo Layout» es gratis?

Sí — el texto completo de «Fundamentos del protocolo Layout» 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 «Fundamentos del protocolo Layout»?

Implemente sizeThatFits y placeSubviews. 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 1 de 4.

¿Cuánto tiempo toma la lección «Fundamentos del protocolo Layout»?

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