0Pricing
Swift Academy · Lezione

Basi del protocollo Layout

Implementi sizeThatFits e placeSubviews.

Basi del protocollo Layout è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 4 lezioni in totale.

Perché un layout personalizzato?

SwiftUI include HStack, VStack e ZStack, ma a volte serve una logica di disposizione che questi componenti non sono in grado di esprimere, come menu radiali, layout a flusso e griglie masonry.

Il protocollo Layout consente di scrivere questa logica continuando a comporla con le normali viste SwiftUI.

Il protocollo Layout

Layout richiede due metodi: sizeThatFits (quanto deve essere grande?) e placeSubviews (dove va ogni elemento figlio?).

Adottate il protocollo in un tipo valore e usatelo come qualsiasi stack integrato.

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

Usare un layout personalizzato

Un valore Layout funge da contenitore. Gli passate le viste figlie nella sua closure finale, esattamente come fareste con uno stack.

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

ProposedViewSize

Il genitore propone una dimensione al vostro layout tramite ProposedViewSize. I suoi valori width e height sono opzionali: nil significa «non specificato, scegliete la vostra dimensione ideale».

I valori speciali .zero, .infinity e .unspecified verificano rispettivamente le dimensioni minima, massima e ideale.

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

sizeThatFits in dettaglio

sizeThatFits restituisce la dimensione desiderata dal vostro layout data una proposta. SwiftUI può chiamarlo più volte con proposte diverse per comprendere la vostra flessibilità.

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 raccolta Subviews

Subviews è una raccolta di proxy, uno per ogni elemento figlio. Ogni proxy restituisce il risultato di sizeThatFits ed espone le priorità di layout e i valori personalizzati.

Non vedete mai le viste reali, ma solo questi proxy di misurazione.

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

placeSubviews

placeSubviews assegna a ogni elemento figlio una posizione all'interno del rettangolo bounds che vi è stato fornito.

Chiamate place(at:anchor:proposal:) su ogni proxy della sottovista.

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

Gli anchor durante il posizionamento

Il parametro anchor indica quale punto dell'elemento figlio viene collocato nella posizione specificata. .topLeading usa l'angolo superiore sinistro; .center centra l'elemento figlio su quel punto.

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

I bounds non iniziano sempre dall'origine

Il rettangolo bounds potrebbe non iniziare in (0,0). Posizionate sempre gli elementi rispetto a bounds.minX e bounds.minY, mai rispetto allo zero assoluto.

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

Un layout minimo con spaziatura uniforme

Ecco un layout che dispone gli elementi figli da sinistra a destra senza spaziatura. I due metodi rimangono coerenti: la dimensione dichiarata corrisponde al posizionamento.

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 coerenza è una vostra responsabilità

SwiftUI si affida alla coerenza dei vostri due metodi. Se placeSubviews usa più spazio di quello dichiarato da sizeThatFits, gli elementi figli potrebbero essere ritagliati o sovrapporsi.

Condividete i calcoli geometrici tra entrambi i metodi.

Verifica rapida: basi dei layout

Verificate la vostra comprensione del protocollo Layout.

Riepilogo: nozioni di base del protocollo Layout

Il protocollo Layout trasforma la logica di disposizione personalizzata in un contenitore riutilizzabile. sizeThatFits restituisce la vostra dimensione per una ProposedViewSize e placeSubviews posiziona ogni proxy figlio all'interno di bounds usando place(at:anchor:proposal:).

Le proposte contengono dimensioni opzionali, i bounds possono essere spostati rispetto all'origine e i due metodi devono rimanere geometricamente coerenti. Ora passeremo a misurare le sottoviste in dettaglio.

Domande Frequenti

La lezione «Basi del protocollo Layout» è gratuita?

Sì — il testo completo di «Basi del protocollo Layout» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 4 lezioni in totale.

Cosa imparerò in «Basi del protocollo Layout»?

Implementi sizeThatFits e placeSubviews. Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Basi del protocollo Layout»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Basi del protocollo Layout
  2. Misurazione delle subview
  3. Creazione di un flow layout
  4. Cache del layout e prestazioni
← Torna a Swift Academy