SwiftUI-Verhalten von .frame (Höhe: Null)

Oct 26 2020

Die Angelegenheit

Ich erhalte ein Thread-Problem mit der Meldung "Ungültige Rahmendimension (negativ oder nicht endlich)".

Hier ist mein Code:

struct CellStyle: ViewModifier {
    func body (Inhalt: Inhalt) -> einige Ansicht {
        Inhalt
            .frame (Breite: .infinity, Höhe: 56, Ausrichtung: .center)
            .padding (.horizontal, 16)
    }}
}}

Der Code läuft gut und ich scheine zu tun, was er soll, also bin ich verwirrt darüber, warum es mir ein Thread-Problem gibt. Warum wird der Code ohne endliche Breite / Höhe ausgeführt, was den Apple-Dokumenten widerspricht? (siehe den Abschnitt "Einige Lesungen" unten)

Die Reparatur

Dieser Code behebt das Problem einwandfrei, aber ich wünschte immer noch, ich hätte verstanden, warum der vorherige Code nicht abstürzt oder einen Fehler verursacht.

struct CellStyle: ViewModifier {
    func body (Inhalt: Inhalt) -> einige Ansicht {
        Inhalt
            .frame (Höhe: 56, Ausrichtung: .center)
            .frame (maxWidth: .infinity)
            .padding (.horizontal, 16)
    }}
}}

Soweit ich das beurteilen kann, gibt es mir dieses Thread-Problem, weil ich sage .frame, dass ich eine Breite möchte, die nicht endlich ist, und eine Breite, die endlich ist.

Weitere Fragen zum Stapelüberlauf

Ich habe zwei Fragen gefunden, die dasselbe stellen:
iOS 14 Ungültige Frame-Dimension (negativ oder nicht endlich)

SwiftUI iOS14 GeometryReader Ungültige Rahmenabmessung

In der ersten Frage ist das Thread-Problem sinnvoll, da es angesichts des Codes .frame(width: p.size.width - padding)keine Garantie gibt, p.size.widthdie kleiner als ist padding. Soweit ich das beurteilen kann, handelt es sich um ein Problem, bei dem der angegebene Wert negativ sein kann.
Dieses Problem hat damit zu tun, dass der angegebene Wert nicht endlich ist, sodass sich die Fragen nicht darauf beziehen.
Die zweite Frage wurde noch nicht beantwortet und ist etwas vage, daher ist sie momentan nicht so hilfreich für mich. Vielleicht antwortet später jemand mit einer hilfreichen Antwort, aber bis jetzt ist es nicht hilfreich.

Etwas lesen

Wenn ich mir die Apple-Dokumente ansehe, finde ich Folgendes:

Verwenden Sie diese Methode, um eine feste Größe für die Breite, Höhe oder beides einer Ansicht anzugeben. Wenn Sie nur eine der Dimensionen angeben, nimmt die resultierende Ansicht das Größenverhalten dieser Ansicht in der anderen Dimension an.

Warum läuft es dann .frame(width: .infinity, height: 56, alignment: .center)überhaupt?
Was bedeutet Apple unter "Die resultierende Ansicht nimmt das Größenverhalten dieser Ansicht in der anderen Dimension an." Wird es immer davon ausgehen, dass diese Ansicht eine "Push-out" -Ansicht ist und somit das gleiche Ergebnis liefert wie .infinity?

Ich habe dies getestet und diesen Code ausgeführt:

struct CellStyle: ViewModifier {
    func body (Inhalt: Inhalt) -> einige Ansicht {
        Inhalt
            .frame (Höhe: 56, Ausrichtung: .center)
            .padding (.horizontal, 16)
    }}
}} 

Es scheint das gleiche Ergebnis zu liefern, also bin ich jetzt neugierig, ob es jemals einen Fall gibt, in dem eine schnelle "Annahme" der Breite zu einem anderen Verhalten führt als .infinity?

Letzte Frage

Was ist der Verhaltensunterschied zwischen .frame(width: .infinity)vs .frame(width: nil)(das Äquivalent der Emission von Breite oder Höhe).

Funktionsrahmen (Breite: CGFloat? = Null, Höhe: CGFloat? = Null, Ausrichtung: Ausrichtung = .center) -> einige Ansicht

Apple-Dokumente

Danke für die Hilfe!

Antworten

1 Asperi Oct 26 2020 at 19:43

Weil es Schnittstellenvertrag dokumentiert ist:

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

Während der Modifikatortyp mit min / max-Argumenten flexible Einschränkungen zulässt (hier nicht kopiert - generiertes SwiftUI-Modul einlesen).

MikaelWeiss Oct 26 2020 at 22:32

Was .frame (width: nil) macht

Grundsätzlich nimmt .frame die angegebenen Werte an und gibt eine andere Ansicht zurück, die mit den von Ihnen angegebenen Werten aktualisiert wird.
Wenn Sie einen der Parameter weglassen oder auf Null setzen, wird der entsprechende Breiten- / Höhenwert der vorherigen Ansicht verwendet.

Testcode:

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

Warum .frame (width: .infinity) immer noch ausgeführt wird

.infinity( Apple-Dokument zu .infinity ) ist vom Typ Float, daher gibt es keine Möglichkeit, es nicht auszuschließen.frame , aber es kann dennoch Probleme verursachen. (Also das Thread-Problem)

Vielen Dank an Mark Moeykens für die Hilfe, die mich zu dieser Antwort gebracht hat!