Budowanie układu przepływowego
Dynamiczne przenoszenie elementów do kolejnych wierszy.
Budowanie układu przepływowego to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 3 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.
Czym jest układ przepływowy?
Układ przepływowy rozmieszcza elementy od lewej do prawej, przenosząc je do nowego wiersza, gdy kolejny element nie zmieściłby się w dostępnej szerokości — podobnie jak znaczniki lub zawijanie tekstu.
Plan
Obliczymy podziały wierszy we wspólnej funkcji pomocniczej, zwrócimy całkowitą wysokość z sizeThatFits i ponownie użyjemy tych samych obliczeń w placeSubviews. Współdzielenie logiki zapewnia spójność obu metod.
Modelowanie rozmieszczenia
Niewielka struktura zapisuje miejsce, w którym ma zostać umieszczony każdy podwidok. Wcześniejsze obliczenie wszystkich rozmieszczeń upraszcza obie metody protokołu.
struct Placement {
let index: Int
let point: CGPoint
let size: CGSize
}Algorytm zawijania
Przejdź po podwidokach, śledząc bieżącą wartość x. Jeśli dziecko przekroczyłoby maksymalną szerokość, wyzeruj x i przesuń się w dół o wysokość wiersza powiększoną o odstęp.
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)
}Implementowanie sizeThatFits
sizeThatFits wykonuje algorytm dla proponowanej szerokości i zwraca szerokość z propozycji oraz obliczoną całkowitą wysokość.
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)
}Implementowanie placeSubviews
placeSubviews wykonuje ten sam algorytm, następnie przesuwa każde rozmieszczenie o bounds.origin i wywołuje 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))
}
}Pełny typ FlowLayout
Połączenie tych elementów daje kompletny, wielokrotnego użytku układ przepływowy. Wspólna funkcja pomocnicza layout gwarantuje zgodność rozmiaru i rozmieszczenia.
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))
}
}
}Korzystanie z układu przepływowego
Można używać go jak dowolnego kontenera. Znaczniki automatycznie przechodzą do kolejnych wierszy, gdy szerokość się zmniejsza.
var body: some View {
FlowLayout {
ForEach(tags, id: \.self) { tag in
Text(tag)
.padding(8)
.background(.blue.opacity(0.2))
.clipShape(Capsule())
}
}
}Obsługa pierwszego elementu w wierszu
Warunek x > 0 zapobiega zawijaniu przed pierwszym elementem wiersza. Bez niego element szerszy niż kontener mógłby powodować nieskończoną pętlę lub niepotrzebnie trafić do pustego wiersza.
if x + size.width > maxWidth, x > 0 {
// wrap only if the row already has content
}Wybór odstępów
W tym przypadku odstęp jest przechowywaną właściwością z wartością domyślną. W kodzie produkcyjnym należy odczytywać preferencję spacing każdego podwidoku, aby respektować metryki systemowe zamiast używać stałej wpisanej na sztywno.
var spacing: CGFloat = 8 // configurable per instanceTestowanie przypadków brzegowych
Przetestuj układ z zerową liczbą elementów, jednym bardzo dużym elementem oraz wieloma małymi elementami. Poprawny układ przepływowy zgłasza wysokość równą zero dla pustej zawartości i nigdy nie przycina pojedynczego dziecka większego niż kontener.
Szybkie sprawdzenie: układ przepływowy
Sprawdź swoją wiedzę na temat algorytmu zawijania.
Podsumowanie: tworzenie układu przepływowego
Układ przepływowy zawija elementy, śledząc bieżącą wartość x i przechodząc do nowego wiersza, gdy kolejny element nie zmieściłby się w dostępnej szerokości. Wspólna funkcja pomocnicza oblicza wszystkie rozmieszczenia i całkowitą wysokość, dzięki czemu sizeThatFits i placeSubviews pozostają spójne.
Przesuwaj rozmieszczenia o bounds.origin, uwzględniaj pierwszy element każdego wiersza i testuj przypadki pustej zawartości, elementów zbyt dużych oraz wielu elementów. Rezultatem jest wielokrotnego użytku kontener zawijający elementy.
Często zadawane pytania
Czy lekcja „Budowanie układu przepływowego” jest bezpłatna?
Tak — pełny tekst „Budowanie układu przepływowego” 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 „Budowanie układu przepływowego”?
Dynamiczne przenoszenie elementów do kolejnych wierszy. Ć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 3 z 4.
Ile czasu zajmuje lekcja „Budowanie układu przepływowego”?
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
- Podstawy protokołu Layout
- Mierzenie podwidoków
- Budowanie układu przepływowego
- Pamięć podręczna układu i wydajność