I have an array that contains a bunch of elements with their preferred alignment. I am trying to add elements from this array to a view through the overlay
modifier. However, I am not able to get it to work. Here is what I’ve tried till now
struct ContentView: View {
struct ViewText {
var label: String
var alignment: Alignment
var id: String
}
var viewArray: [ViewText] = [
ViewText(label: "Hello 1", alignment: .topLeading, id: "1"),
ViewText(label: "Hello 2", alignment: .topTrailing, id: "2"),
ViewText(label: "Hello 3", alignment: .bottomLeading, id: "3"),
ViewText(label: "Hello 4", alignment: .bottomTrailing, id: "4")
]
var body: some View {
var backgroundView = Rectangle().frame(width: 100, height: 100).background(Color.red)
ForEach(viewArray, id: .id) { element in
backgroundView.overlay(alignment: element.alignment) {
Text(element.label).foregroundColor(.white)
}
}
}
}
The above code does not work. It adds multiple background views for each overlay that is present in the array. Any idea on how I can get it to work? Thanks a lot for your time
2
Answers
Use a
ZStack
, which can work withForEach
, and also overlays views on top of each other.Note that I used
maxWidth: .infinity, maxHeight: .infinity
to make theZStack
to match the frame of theRectangle
.Output:
Sweeper got there first: the key to getting it working is to use a
ZStack
. This is becauseForEach
does not layer its contents by default.Reading the comments to his answer, it sounds like a
Grid
might be a simpler way of achieving the layout you want. But for a simple 2×2 arrangement, it can be done with frame alignment if you really want.Here’s a version that picks up on the comments to Sweeper’s answer. More notes below.
Notes:
body
. To keep the code a bit structured I have moved the colored rectangle to a function instead.ZStack
is 200×200. Within theZstack
, each 100×100 rectangle is expanded to the full available width and height, with alignment re-applied to these nested frames too.