Another Dude
Another Dude

Reputation: 1454

SwiftUI : stack overlapping elements horizontally?

I would like to stack overlapping elements horizontally, like this:

enter image description here

Here is what I tried:

struct StackedElementsView: View {
    let colors: [Color] = [.red, .blue, .purple]
    
    var body: some View {
        HStack {
            ZStack {
                ForEach(0..<colors.count) { i in
                    ZStack(alignment: .leading) {
                        colors[i]
                            .clipShape(Circle())
                            .frame(width: 44, height: 44)
                    }
                    .offset(x: CGFloat(i) * 25)
                }
            }
            .padding(.leading, 24)
            Color.purple
                .frame(width: 100, height: 44)
            Spacer()
        }
        .padding(.vertical, 8)
    }
}

struct StackedElementsView_Previews: PreviewProvider {
    static var previews: some View {
        StackedElementsView()
    }
}

I have an issue with this, the purple rectangle overlaps the circles and I don't know why.

Thank you for your help

Upvotes: 7

Views: 4644

Answers (2)

vacawama
vacawama

Reputation: 154543

.offset just changes where the view draws, but doesn't change the frame which is why the rectangle draws further left than you expect.

One way to fix this is to add appropriate leading padding to the rectangle:

Color.purple
    .frame(width: 100, height: 44)
    .padding(.leading, CGFloat(colors.count - 1) * 25)

Alternate solution

Instead of using .offset, use a Color.clear view in an HStack to provide the spacing needed:

ForEach(0..<colors.count) { i in
    ZStack(alignment: .leading) {
        HStack(spacing: 0) {
            Color.clear
                .frame(width: CGFloat(i) * 25, height: 44)
            colors[i]
                .clipShape(Circle())
                .frame(width: 44, height: 44)
        }
    }
}

Upvotes: 2

Kai Zheng
Kai Zheng

Reputation: 8130

Here would be a more intuitive solution. You could instead use negative spacing and have only HStacks:

enter image description here

struct StackedElementsView: View {
    let colors: [Color] = [.red, .blue, .purple]
    
    var body: some View {
        HStack {
            HStack(spacing: -25) {
                ForEach(0..<colors.count) { i in
                    colors[i]
                        .clipShape(Circle())
                        .frame(width: 44, height: 44)
                }
            }
            
            Color.purple
                .frame(width: 100, height: 44)
            Spacer()
        }
        .padding(.leading, 24)
        .padding(.vertical, 8)
    }
}

Upvotes: 11

Related Questions