skip to Main Content

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 result of the above code
Result of the above code

Expected Result
Expected result

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


  1. Use a ZStack, which can work with ForEach, and also overlays views on top of each other.

    Rectangle().frame(width: 100, height: 100)
        .overlay {
            ZStack {
                ForEach(viewArray, id: .id) { element in
                    Text(element.label).foregroundColor(.white)
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: element.alignment)
                }
            }
        }
    

    Note that I used maxWidth: .infinity, maxHeight: .infinity to make the ZStack to match the frame of the Rectangle.

    Output:

    enter image description here

    Login or Signup to reply.
  2. Sweeper got there first: the key to getting it working is to use a ZStack. This is because ForEach 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.

    struct ContentView: View {
        struct ViewText {
            var label: String
            var alignment: Alignment
            var id: String
            var color: Color
        }
    
        var viewArray: [ViewText] = [
            ViewText(label: "Hello 1", alignment: .topLeading, id: "1", color: .red),
            ViewText(label: "Hello 2", alignment: .topTrailing, id: "2", color: .blue),
            ViewText(label: "Hello 3", alignment: .bottomLeading, id: "3", color: .green),
            ViewText(label: "Hello 4", alignment: .bottomTrailing, id: "4", color: .purple)
        ]
    
        private func coloredRectangle(color: Color) -> some View {
            color
                .frame(width: 100, height: 100)
        }
    
        var body: some View {
            ZStack {
                ForEach(viewArray, id: .id) { element in
                    coloredRectangle(color: element.color)
                        .overlay(alignment: element.alignment) {
                            Text(element.label).foregroundColor(.white)
                        }
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: element.alignment)
                }
            }
            .frame(width: 200, height: 200)
        }
    }
    

    Notes:

    • As you will see, I have added a color to each Rectangle.
    • I would not assign a view to a variable within body. To keep the code a bit structured I have moved the colored rectangle to a function instead.
    • To get the grid effect, each rectangle is 100×100 and the ZStack is 200×200. Within the Zstack, each 100×100 rectangle is expanded to the full available width and height, with alignment re-applied to these nested frames too.
      ColoredRectangle
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search