Zachowanie SwiftUI .frame (wysokość: zero)
Problem
Pojawia się problem z wątkiem, który mówi „Nieprawidłowy wymiar ramki (ujemny lub nieskończony)”.
Oto mój kod:
struct CellStyle: ViewModifier {
func body (content: Content) -> some View {
zadowolony
.frame (szerokość: .infinity, wysokość: 56, wyrównanie: .center)
.padding (.horizontal, 16)
}
}
Kod działa dobrze i wydaje mi się, że robi to, co powinien, więc jestem zdezorientowany, dlaczego powoduje to problem z wątkiem. Dlaczego kod będzie działał bez skończonej szerokości / wysokości, co jest sprzeczne z dokumentacją Apple? (zobacz sekcję „Trochę czytania” poniżej)
Poprawka
Ten kod dobrze rozwiązuje problem, ale nadal chciałbym zrozumieć, dlaczego poprzedni kod nie ulega awarii lub nie powoduje błędu.
struct CellStyle: ViewModifier {
func body (content: Content) -> some View {
zadowolony
.frame (wysokość: 56, wyrównanie: .center)
.frame (maxWidth: .infinity)
.padding (.horizontal, 16)
}
}
O ile wiem, daje mi to problem z wątkiem, ponieważ mówię .frame, że chcę szerokości, która nie jest skończona, a szerokość, która jest skończona.
Inne pytania dotyczące przepełnienia stosu
Znalazłem dwa pytania, które zadają to samo:
iOS 14 Nieprawidłowy wymiar ramki (ujemny lub nieskończony)
SwiftUI iOS14 GeometryReader Nieprawidłowy wymiar ramki
W pierwszym pytaniu kwestia wątków ma sens, ponieważ biorąc pod uwagę kod, .frame(width: p.size.width - padding)nie ma gwarancji, że p.size.widthbędzie mniejsza niż padding. O ile wiem, jest to problem, w którym podana wartość może być ujemna.
Ten problem, który mam, dotyczy tego, że podana wartość nie jest skończona, więc pytania nie odnoszą się do siebie.
Na drugie pytanie nadal nie ma odpowiedzi i jest trochę niejasne, więc nie jest dla mnie teraz takie pomocne. Może później ktoś odpowie pomocną odpowiedzią, ale na razie nie jest ona pomocna.
Trochę czytania
Patrząc na dokumenty Apple , znajduję to:
Użyj tej metody, aby określić stały rozmiar szerokości, wysokości widoku lub obu. Jeśli określisz tylko jeden z wymiarów, wynikowy widok przyjmie zachowanie rozmiaru tego widoku w drugim wymiarze.
Więc dlaczego w .frame(width: .infinity, height: 56, alignment: .center)ogóle działa?
Co Apple rozumie przez „wynikowy widok zakłada zachowanie rozmiaru tego widoku w innym wymiarze”? Czy zawsze przyjmie, że ten widok jest widokiem „wypychającym”, dając w ten sposób ten sam wynik co .infinity?
Przetestowałem to i uruchomiłem ten kod:
struct CellStyle: ViewModifier {
func body (content: Content) -> some View {
zadowolony
.frame (wysokość: 56, wyrównanie: .center)
.padding (.horizontal, 16)
}
}
Wydaje się, że daje ten sam rezultat, więc teraz jestem ciekawy, czy był kiedyś przypadek, w którym szybkie „przyjęcie” szerokości spowoduje zachowanie inne niż .infinity?
Ostatnie pytanie
Jaka jest różnica w zachowaniu między .frame(width: .infinity)vs .frame(width: nil)(odpowiednik emitowania szerokości lub wysokości).
func frame (width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> some View
Dokumenty Apple
Dzięki za pomoc!
Odpowiedzi
Ponieważ jest to udokumentowana umowa dotycząca interfejsu:
/// - Parameters:
/// - width: A fixed width for the resulting view. If `width` is `nil`,
/// the resulting view assumes this view's sizing behavior.
/// - height: A fixed height for the resulting view. If `height` is `nil`,
/// the resulting view assumes this view's sizing behavior.
/// - alignment: The alignment of this view inside the resulting view.
/// `alignment` applies if this view is smaller than the size given by
/// the resulting frame.
///
/// - Returns: A view with fixed dimensions of `width` and `height`, for the
/// parameters that are non-`nil`.
@inlinable public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> some View
podczas gdy typ modyfikatora z argumentami min / max pozwala na elastyczne ograniczenia (nie kopiowane tutaj - wczytaj w wygenerowanym module SwiftUI).
Co robi .frame (width: nil)
Zasadniczo .frame przyjmie podane wartości i zwróci inny widok, który jest aktualizowany wprowadzonymi wartościami.
Jeśli pominiesz jeden z parametrów lub ustawisz go na zero, przyjmie on odpowiednią wartość szerokości / wysokości poprzedniego widoku.
Kod testowy:
struct ContentView: View {
@State var keyValue = ""
var body: some View {
VStack(spacing: 10) {
Text("Something")
.background(Color.blue)
Text("Something")
.frame(width: 300, height: nil, alignment: .center)
.background(Color.blue)
Text("Something")
.frame(width: nil, height: 200, alignment: .center)
.background(Color.blue)
Text("Something")
.frame(width: nil, height: nil, alignment: .center)
.background(Color.blue)
}
}
}
Dlaczego .frame (width: .infinity) nadal działa
.infinity( Dokument Apple na .infinity ) jest typowyFloat , więc nie można tego nie robić.frame , ale nadal może powodować problemy. (Stąd kwestia wątku)
Dziękuję Markowi Moeykensowi za pomoc w uzyskaniu tej odpowiedzi!