Search code examples
arraysswiftuiforeachscroll

SwiftUI: Vertical Scrollview doesn’t scroll at all, when using ZStack


I am iterating an array of simple structs, containing a name and a color. For each element I am displaying a rectangle with the specified color and a machting text element.

All of this is inside a ZStack, so be able to se all the elements, I am offsetting the rectangles, depending on their index in the array.

The problem is, I am trying to create a vertical scrollView, but it wont scroll. I keeps snapping back to the top.

This is my code:

ScrollView{
    ZStack {
        
        ForEach(Array(bookTags.enumerated()), id: \.element.id) { index, tag in
            Rectangle()
                .frame(height: 300)
                .edgesIgnoringSafeArea(.bottom)
                .foregroundColor(Color(hex: tag.color))
                .overlay {
                    VStack {
                        HStack {
                            Text(tag.name)
                                .font(.system(size: 30, weight: .bold, design: .rounded))
                                .foregroundColor(.white)
                            
                            Spacer()
                        }
                        .padding(.horizontal, 30)
                        
                        
                        Spacer()
                    }
                    .padding(.top, 30)
                }
                .offset(y: index != 0 ? CGFloat(index) * 75: 0)
        } // foreach
        
        
    } // zstack

} // scroll

UPDATE

Since .offset does not change the height of the container, I tried using .padding(.top, index != 0 ? CGFloat(index) * 75 : 0)

This seems to fix the scroll issue. But for some reason the last element becomes all weird and funny looking. Like this:

enter image description here

UPDATE 2

When I add this line:

.padding(.top, index != 0 ? CGFloat(index) * 75 : 0)

and remove:

.offset(y: index != 0 ? CGFloat(index) * 75: 0)

I also have to remove the framing of the rectangle, if I dont I get this weird behaviour:

enter image description here


Solution

  • When you use offset to change the position of a view, it has no impact on the size of the view, so it has no impact on the size of its container either. This means, your ZStack will only have a height of 300.

    Instead of using .offset, you could add top padding to the rectangles instead:

        //.offset(y: index != 0 ? CGFloat(index) * 75: 0)
        .padding(.top, index != 0 ? CGFloat(index) * 75: 0)
    

    UPDATE
    Following your updates and answers, two more suggested changes:

    1. Remove .edgesIgnoringSafeArea(.bottom) from the rectangles
    2. Apply these changes to the ScrollView and ZStack:
        ScrollView {
           ZStack(alignment: .top) { // alignment added
                // content as before
           }
        }
        .edgesIgnoringSafeArea(.bottom)