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

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
Here would be a more intuitive solution. You could instead use negative spacing and have only HStacks:

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)
}
}
.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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With