Reputation: 4262
I've tried this code and set alignment of the nested view to .top. But it's still cenetered.
struct ContentView: View {
var body: some View {
ZStack {
Rectangle().fill(Color.red).frame(maxWidth: .infinity, maxHeight: 100, alignment: .top)
}
}
}
Upvotes: 2
Views: 7435
Reputation: 1
You do not need use Rectangle for this work, use Color instead, it make your View be cheaper/faster in render and less CPU than using Rectangle and then trying to fill it with Color.
struct ContentView: View {
var body: some View {
ZStack {
Color.yellow
VStack {
Color.red.frame(height: 100)
Spacer()
Color.blue.frame(height: 100)
}
}
}
}
Upvotes: 4
Reputation: 246
You can try this :
struct ContentView: View {
var body: some View {
ZStack(alignment: .top) {
Rectangle()
.fill(Color.red)
.frame(maxWidth: .infinity, maxHeight: 100)
}
}
}
Upvotes: 0
Reputation: 299613
The answers here are good, but it's worth diving into why you were confused in the first place. Let's look at your code:
ZStack {
Rectangle()
.fill(Color.red)
.frame(maxWidth: .infinity, maxHeight: 100, alignment: .top)
}
This is a Rectangle, enclosed in a Fill, enclosed in a Frame, enclosed in a ZStack. Each of these is its own View.
First, the Rectangle declares that it will fill whatever space it is offered with a stroked and filled rectangle, using whatever stroke and fill color are set by its parents.
The Fill, which wraps the Rectangle, sets the fill color to red for its children.
The Frame offers "the lessor of what the Frame is offered and infinity" as the width and "the lessor of what the Frame is offered and 100" as the hight to its children. Its children (the Fill, which contains the Rectangle), accept all the space they're offered, which in the end will be "the width of the screen and 100 points high." The frame sets its own width to this, and aligns its one child at the top.
The ZStack offers the whole screen size to the Frame. When the Frame is done, the ZStack sets its own size to the size of its children (the Frame), and centers its children (since that's its alignment).
The containing View (which is the size of the screen), then centers the small ZStack.
The key point is that the .top
applies to the Frame, not the ZStack, and not the entire View.
So how do you get what you want? First of all, you want the ZStack to be the size of the entire View. That means its children must be the size of the entire View. A ZStack is always the exact size of its children.
But really, the natural way to do what you're describing is with a VStack, since you really want a vertical stack of views:
VStack {
Rectangle().fill(Color.red).frame(height: 100)
Spacer()
}
Or as Swiftpunk points out, you can use Color directly, though it's a trivial difference. It just is a little shorter in code. Setting the width here isn't meaningful.
VStack {
Color.red.frame(maxHeight: 100)
Spacer()
}
If you wanted a ZStack (I don't know why, but if you did), then you could achieve the same thing by forcing the ZStack to be as big as it's offered by including a Color, and then also ask it to align its elements at the topLeading.
ZStack(alignment: .topLeading) {
Color.clear // Color is always as large as the space offered
Color.red.frame(maxHeight: 100)
}
Upvotes: 1
Reputation: 3018
Another very direct way of doing it - you need a GeometryReader
but to position the x
not the y
.
GeometryReader { reader in
ZStack {
Rectangle()
.fill ( Color.red )
.frame ( height: h )
.position ( x: 0.5 * reader.size.width, y: 0.5 * h )
}
}
Here h
is the desired height.
Upvotes: 2
Reputation: 52615
The surrounding ZStack
needs to have a frame that will take up the whole view -- otherwise it'll just be the height of the rectangle. It's also the one that needs the .top
alignment:
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color.red)
.frame(height: 100)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
Update, based on comment:
struct ContentView: View {
var body: some View {
ZStack {
VStack {
Rectangle()
.fill(Color.red)
.frame(height: 100)
Spacer()
Rectangle()
.fill(Color.green)
.frame(height: 100)
}
}
}
}
Upvotes: 2