Angesichts dieses Codes:
import SwiftUI
struct ContentView : View {
var body: some View {
VStack(alignment: .leading) {
Text("Title")
.font(.title)
Text("Content")
.lineLimit(nil)
.font(.body)
Spacer()
}
.background(Color.red)
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Daraus ergibt sich diese Wechselwirkung:
Wie kann ich VStack
die Breite des Bildschirms ausfüllen, auch wenn die Beschriftungen / Textkomponenten nicht die volle Breite benötigen?
Ein Trick, den ich gefunden habe, besteht darin, ein Leerzeichen HStack
wie folgt in die Struktur einzufügen :
VStack(alignment: .leading) {
HStack {
Spacer()
}
Text("Title")
.font(.title)
Text("Content")
.lineLimit(nil)
.font(.body)
Spacer()
}
Welches ergibt das gewünschte Design:
Gibt es einen besseren Weg?
Antworten:
Versuchen Sie, den Modifikator .frame mit den folgenden Optionen zu verwenden:
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
struct ContentView: View { var body: some View { VStack(alignment: .leading) { Text("Hello World").font(.title) Text("Another").font(.body) Spacer() }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading ).background(Color.red) } }
Dies wird als flexibler Rahmen beschrieben ( siehe Dokumentation ), der sich ausdehnt, um den gesamten Bildschirm auszufüllen, und wenn er zusätzlichen Platz hat, zentriert er seinen Inhalt darin.
quelle
.leading
). Nimmt die volle Breite ein, wenn vor.background(Color.red)
.backgound(Color.red)
ist der Hintergrund der Rahmenansicht, jedoch nicht der HintergrundVStack
der Rahmenansicht. (Der Grund dafür wird in den WWDC-Videos erklärt: P). Wenn Sie.background(Color.green)
vor das setzen, sehen.frame
Sie, dass dasVStack
Standbild eine Breite hat, die zu seinem Inhalt passt, während der Rahmen einen roten Hintergrund hat ... Wenn Sie das setzen.frame(...)
, wird das nicht bearbeitetVStack
, sondern es wird tatsächlich eine andere Ansicht erstellt.Eine alternative Stapelanordnung, die funktioniert und vielleicht etwas intuitiver ist, ist die folgende:
struct ContentView: View { var body: some View { HStack() { VStack(alignment: .leading) { Text("Hello World") .font(.title) Text("Another") .font(.body) Spacer() } Spacer() }.background(Color.red) } }
Der Inhalt kann bei Bedarf auch einfach neu positioniert werden, indem die entfernt
Spacer()
werden.quelle
Es gibt einen besseren Weg!
Um die
VStack
Füllung auf die Breite des übergeordneten Elements zu bringen, können Sie a verwendenGeometryReader
und den Rahmen festlegen. (.relativeWidth(1.0)
sollte funktionieren, aber anscheinend gerade nicht)struct ContentView : View { var body: some View { GeometryReader { geometry in VStack { Text("test") } .frame(width: geometry.size.width, height: nil, alignment: .topLeading) } } }
Um
VStack
die Breite des tatsächlichen Bildschirms zu bestimmen, können SieUIScreen.main.bounds.width
beim Festlegen des Rahmens anstelle von a verwendenGeometryReader
, aber ich kann mir vorstellen, dass Sie wahrscheinlich die Breite der übergeordneten Ansicht wollten.Diese Methode hat auch den zusätzlichen Vorteil
VStack
, dass Sie keinen Abstand hinzufügen, was passieren kann (wenn Sie einen Abstand haben), wenn Sie einenHStack
mit einemSpacer()
Inhalt als Inhalt zum hinzufügenVStack
.UPDATE - ES GIBT KEINEN BESSEREN WEG!
Nachdem ich die akzeptierte Antwort überprüft hatte, stellte ich fest, dass die akzeptierte Antwort nicht wirklich funktioniert! Es scheint auf den ersten Blick zu funktionieren, aber wenn Sie das aktualisieren
VStack
, um einen grünen Hintergrund zu erhalten, werden Sie feststellen, dassVStack
es immer noch dieselbe Breite hat.struct ContentView : View { var body: some View { NavigationView { VStack(alignment: .leading) { Text("Hello World") .font(.title) Text("Another") .font(.body) Spacer() } .background(Color.green) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) .background(Color.red) } } }
Dies liegt daran
.frame(...)
, dass der Ansichtshierarchie tatsächlich eine weitere Ansicht hinzugefügt wird und diese Ansicht den Bildschirm ausfüllt. DasVStack
tut das aber immer noch nicht.Dieses Problem scheint auch in meiner Antwort dasselbe zu sein und kann mit demselben Ansatz wie oben überprüft werden (wobei verschiedene Hintergrundfarben vor und nach dem gesetzt werden
.frame(...)
. Die einzige Möglichkeit, die tatsächlich zu erweitern scheint,VStack
ist die Verwendung von Abstandshaltern:struct ContentView : View { var body: some View { VStack(alignment: .leading) { HStack{ Text("Title") .font(.title) Spacer() } Text("Content") .lineLimit(nil) .font(.body) Spacer() } .background(Color.green) } }
quelle
relativeWidth
, hat nicht funktioniert. Funktioniert irgendwie,GeometryReader
wenn.frame
vor.background(Color.red)
GeometryReader
in der angezeigten Liste nicht sehen , wenn ich "Modifikator hinzufügen" nach IShow SwiftUI Inspector
oder irgendwo anders in der Benutzeroberfläche. Wie haben Sie entdecktGeometryReader
?Mit Swift 5.2 und iOS 13.4 können Sie je nach Bedarf eines der folgenden Beispiele verwenden, um Ihre Anforderungen an die wichtigsten
VStack
Einschränkungen und einen Rahmen in voller Größe anzupassen.Beachten Sie, dass die folgenden Codeausschnitte zu derselben Anzeige führen, jedoch weder den effektiven Frame
VStack
noch die Anzahl derView
Elemente garantieren, die beim Debuggen der Ansichtshierarchie angezeigt werden.1.
frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)
Methode verwendenDer einfachste Ansatz besteht darin, den Rahmen Ihres
VStack
mit maximaler Breite und Höhe einzustellen und die erforderliche Ausrichtung zu übergeben inframe(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)
:struct ContentView: View { var body: some View { VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) } .frame( maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading ) .background(Color.red) } }
Wenn das Festlegen des maximalen Rahmens mit einer bestimmten Ausrichtung für Ihr
View
s ein häufiges Muster in Ihrer Codebasis ist, können Sie alternativ eine Erweiterungsmethode dafür erstellenView
:extension View { func fullSize(alignment: Alignment = .center) -> some View { self.frame( maxWidth: .infinity, maxHeight: .infinity, alignment: alignment ) } } struct ContentView : View { var body: some View { VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) } .fullSize(alignment: .topLeading) .background(Color.red) } }
2. Verwenden Sie
Spacer
s, um die Ausrichtung zu erzwingenSie können Ihr
VStack
Inneres in voller Größe einbettenHStack
und Trailing und BottomSpacer
s verwenden, um IhreVStack
Ausrichtung nach oben zu erzwingen :struct ContentView: View { var body: some View { HStack { VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) Spacer() // VStack bottom spacer } Spacer() // HStack trailing spacer } .frame( maxWidth: .infinity, maxHeight: .infinity ) .background(Color.red) } }
3. Verwenden Sie einen
ZStack
Hintergrund in voller GrößeView
Dieses Beispiel zeigt, wie Sie Ihr
VStack
Inneres einbettenZStack
, das eine Ausrichtung nach oben aufweist. Beachten Sie, wie in derColor
Ansicht die maximale Breite und Höhe festgelegt wird:struct ContentView: View { var body: some View { ZStack(alignment: .topLeading) { Color.red .frame(maxWidth: .infinity, maxHeight: .infinity) VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) } } } }
4. Verwenden von
GeometryReader
GeometryReader
hat die folgende Erklärung :Das folgende Code-Snippet zeigt, wie Sie es
GeometryReader
an den wichtigstenVStack
Einschränkungen und einem Rahmen in voller Größe ausrichten können :struct ContentView : View { var body: some View { GeometryReader { geometryProxy in VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) } .frame( width: geometryProxy.size.width, height: geometryProxy.size.height, alignment: .topLeading ) } .background(Color.red) } }
5.
overlay(_:alignment:)
Methode verwendenWenn Sie Ihre
VStack
mit den wichtigsten Einschränkungen über einer vorhandenen Größe in voller Größe ausrichten möchtenView
, können Sie folgendeoverlay(_:alignment:)
Methode verwenden:struct ContentView: View { var body: some View { Color.red .frame( maxWidth: .infinity, maxHeight: .infinity ) .overlay( VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .font(.body) }, alignment: .topLeading ) } }
Anzeige:
quelle
Der einfachste Weg, das Problem zu lösen, war die Verwendung eines ZStack + .edgesIgnoringSafeArea (.all).
struct TestView : View { var body: some View { ZStack() { Color.yellow.edgesIgnoringSafeArea(.all) VStack { Text("Hello World") } } } }
quelle
Sie können es mit tun
GeometryReader
GeometryReader
Code:
struct ContentView : View { var body: some View { GeometryReader { geometry in VStack { Text("Turtle Rock").frame(width: geometry.size.width, height: geometry.size.height, alignment: .topLeading).background(Color.red) } } } }
Ihre Ausgabe mag:
quelle
benutze das
quelle
Eine gute Lösung und ohne "Erfindungen" ist das Vergessene
ZStack
ZStack(alignment: .top){ Color.red VStack{ Text("Hello World").font(.title) Text("Another").font(.body) } }
Ergebnis:
quelle
Eine weitere Alternative besteht darin, eine der Unteransichten innerhalb von a
HStack
undSpacer()
danach zu platzieren:struct ContentView : View { var body: some View { VStack(alignment: .leading) { HStack { Text("Title") .font(.title) .background(Color.yellow) Spacer() } Text("Content") .lineLimit(nil) .font(.body) .background(Color.blue) Spacer() } .background(Color.red) } }
ergebend :
quelle
Dies hat bei mir funktioniert (
ScrollView
(optional), sodass bei Bedarf weitere Inhalte hinzugefügt werden können, plus zentrierte Inhalte):import SwiftUI struct SomeView: View { var body: some View { GeometryReader { geometry in ScrollView(Axis.Set.horizontal) { HStack(alignment: .center) { ForEach(0..<8) { _ in Text("🥳") } }.frame(width: geometry.size.width, height: 50) } } } } // MARK: - Preview #if DEBUG struct SomeView_Previews: PreviewProvider { static var previews: some View { SomeView() } } #endif
quelle
Ich weiß, dass dies nicht für alle funktionieren wird, aber ich fand es interessant, dass nur das Hinzufügen eines Teilers dies löst.
struct DividerTest: View { var body: some View { VStack(alignment: .leading) { Text("Foo") Text("Bar") Divider() }.background(Color.red) } }
quelle
Dies ist ein nützlicher Code:
extension View { func expandable () -> some View { ZStack { Color.clear self } } }
Vergleichen Sie die Ergebnisse mit und ohne
.expandable()
Modifikator:Text("hello") .background(Color.blue)
- -
Text("hello") .expandable() .background(Color.blue)
quelle
Sie können GeometryReader in einer praktischen Erweiterung verwenden, um das übergeordnete Element zu füllen
extension View { func fillParent(alignment:Alignment = .center) -> some View { return GeometryReader { geometry in self .frame(width: geometry.size.width, height: geometry.size.height, alignment: alignment) } } }
Wenn Sie also das angeforderte Beispiel verwenden, erhalten Sie
struct ContentView : View { var body: some View { VStack(alignment: .leading) { Text("Title") .font(.title) Text("Content") .lineLimit(nil) .font(.body) } .fillParent(alignment:.topLeading) .background(Color.red) } }
(Beachten Sie, dass der Abstandshalter nicht mehr benötigt wird.)
quelle
Anmeldeseitengestaltung mit
SwiftUI
import SwiftUI struct ContentView: View { @State var email: String = "[email protected]" @State var password: String = "" @State static var labelTitle: String = "" var body: some View { VStack(alignment: .center){ //Label Text("Login").font(.largeTitle).foregroundColor(.yellow).bold() //TextField TextField("Email", text: $email) .textContentType(.emailAddress) .foregroundColor(.blue) .frame(minHeight: 40) .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green)) TextField("Password", text: $password) //Placeholder .textContentType(.newPassword) .frame(minHeight: 40) .foregroundColor(.blue) // Text color .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green)) //Button Button(action: { }) { HStack { Image(uiImage: UIImage(named: "Login")!) .renderingMode(.original) .font(.title) .foregroundColor(.blue) Text("Login") .font(.title) .foregroundColor(.white) } .font(.headline) .frame(minWidth: 0, maxWidth: .infinity) .background(LinearGradient(gradient: Gradient(colors: [Color("DarkGreen"), Color("LightGreen")]), startPoint: .leading, endPoint: .trailing)) .cornerRadius(40) .padding(.horizontal, 20) .frame(width: 200, height: 50, alignment: .center) } Spacer() }.padding(10) .frame(minWidth: 0, idealWidth: .infinity, maxWidth: .infinity, minHeight: 0, idealHeight: .infinity, maxHeight: .infinity, alignment: .top) .background(Color.gray) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
quelle