0Pricing
Swift Academy · Lekcja

Podstawy protokołu Layout

Implementowanie sizeThatFits i placeSubviews.

Podstawy protokołu Layout to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 4 lekcji w sumie.

Po co tworzyć własny układ?

SwiftUI zawiera elementy HStack, VStack i ZStack, ale czasami potrzebna jest logika rozmieszczania, której nie da się w nich wyrazić — na przykład menu radialne, układy przepływowe lub siatki masonry.

Protokół Layout pozwala napisać taką logikę, zachowując możliwość komponowania ze zwykłymi widokami SwiftUI.

Protokół Layout

Protokół Layout wymaga dwóch metod: sizeThatFits (jak duży powinienem być?) oraz placeSubviews (gdzie umieścić każde dziecko?).

Spełniasz go dla typu wartości i używasz go tak jak każdego wbudowanego stosu.

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

Używanie własnego układu

Wartość typu Layout działa jak kontener. Widoki potomne przekazuje się w jego domknięciu końcowym, dokładnie tak jak w przypadku stosu.

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

ProposedViewSize

Rodzic przekazuje propozycję rozmiaru układowi za pośrednictwem ProposedViewSize. Jego właściwości width i height są opcjonalne: nil oznacza „nieokreślony, wybierz rozmiar idealny”.

Wartości specjalne .zero, .infinity i .unspecified służą do sprawdzania odpowiednio rozmiaru minimalnego, maksymalnego i idealnego.

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

sizeThatFits szczegółowo

sizeThatFits zwraca rozmiar wybrany przez układ dla danej propozycji. SwiftUI może wywołać tę metodę wielokrotnie z różnymi propozycjami, aby określić elastyczność układu.

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

Kolekcja Subviews

Subviews to kolekcja proxy dla każdego elementu potomnego. Każde proxy odpowiada na sizeThatFits i udostępnia priorytety układu oraz wartości niestandardowe.

Nie uzyskujesz dostępu do rzeczywistych widoków — widzisz wyłącznie te proxy pomiarowe.

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

placeSubviews

placeSubviews przypisuje każdemu elementowi potomnemu pozycję wewnątrz przekazanego prostokąta bounds.

Wywołaj place(at:anchor:proposal:) na każdym proxy podwidoku.

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

Punkty zakotwiczenia podczas rozmieszczania

Parametr anchor określa, który punkt elementu potomnego zostanie umieszczony w podanej pozycji. .topLeading pozycjonuje element względem jego lewego górnego rogu, a .center wyśrodkowuje go względem tej pozycji.

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

Granice nie zawsze zaczynają się w początku układu

Prostokąt bounds może nie zaczynać się w punkcie (0,0). Zawsze pozycjonuj elementy względem bounds.minX i bounds.minY, nigdy względem bezwzględnego zera.

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

Minimalny układ z równymi odstępami

Łącząc wszystko, otrzymujemy układ, który rozmieszcza elementy potomne od lewej do prawej bez odstępów. Obie metody pozostają spójne: zgłoszony rozmiar odpowiada rozmieszczeniu.

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

Za spójność odpowiadasz Państwo

SwiftUI zakłada, że obie metody są ze sobą zgodne. Jeśli placeSubviews używa więcej miejsca, niż zgłoszono w sizeThatFits, elementy potomne mogą zostać przycięte lub nachodzić na siebie.

Współdziel obliczenia geometrii między obiema metodami.

Szybki sprawdzian: podstawy Layout

Sprawdź swoją znajomość protokołu Layout.

Podsumowanie: podstawy protokołu Layout

Protokół Layout przekształca niestandardową logikę rozmieszczania w kontener wielokrotnego użytku. sizeThatFits zgłasza rozmiar dla obiektu ProposedViewSize, a placeSubviews umieszcza każde proxy elementu potomnego wewnątrz bounds za pomocą place(at:anchor:proposal:).

Propozycje zawierają opcjonalne wymiary, granice mogą być przesunięte względem początku układu, a obie metody muszą zachowywać spójność geometryczną. Następnie szczegółowo zmierzymy podwidoki.

Często zadawane pytania

Czy lekcja „Podstawy protokołu Layout” jest bezpłatna?

Tak — pełny tekst „Podstawy protokołu Layout” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Podstawy protokołu Layout”?

Implementowanie sizeThatFits i placeSubviews. Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Swift Academy?

Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Podstawy protokołu Layout”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?

Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy protokołu Layout
  2. Mierzenie podwidoków
  3. Budowanie układu przepływowego
  4. Pamięć podręczna układu i wydajność
← Powrót do Swift Academy