SwiftUI ScrollView can't scroll down to all the content of ZStack

98 views Asked by At

SwiftUI ScrollView can't scroll all down to all the content of the included ZStack.

struct TestView: View {
    var colors: [Color] = [.red, .orange, .yellow, .green, .mint, .teal, .cyan, .blue, .indigo, .purple, .pink, .brown ]

    var body: some View {
        ScrollView {
            ZStack {
                ForEach(0..<10) {i in
                    RoundedRectangle(cornerSize: CGSize(width: 30, height: 30))
                        .fill(colors[i])
                        .frame(width: 300, height: 300 )
                        .offset(x: 0, y: CGFloat(i) * 200)
                }
            }
        }
    }
}
2

There are 2 answers

1
ColdLogic On BEST ANSWER

The problem you have is from using ZStack and offset together. offset doesn't adjust the frame of the view. If you set the background color of your ZStack, you will notice it doesn't contain all of the rectangles.

enter image description here

Also, the default alignment of a ZStack is .center which would not be what you want.

To fix your problem, there are many things you can do. For one, you can add a vertical padding to each view, in place of the offset. Also set the alignment of the ZStack the top:

    var body: some View {
        ScrollView() {
            ZStack(alignment: .top) {
                ForEach(0..<colors.count) { index in
                    RoundedRectangle(cornerRadius: 30)
                        .fill(colors[index])
                        .frame(width: 300, height: 300)
                        .padding(.top, CGFloat(index) * 100)
                }
            }
        }
    }

enter image description here

1
rich On

Thank ColdLogic for pointing the two key points: offset doesn't change the size of ZStack; ZStack's default alignment is center. So it seems the only way to use ScrollView and ZStack with offset is to set the frame height to the actual height of its content of the ZStack.

Here is the code:

struct TestView: View {
    var colors: [Color] = [.red, .orange, .yellow, .green, .mint, .teal, .cyan, .blue, .indigo, .purple, .pink, .brown ]

    var body: some View {
        ScrollView {
                ZStack(alignment: .top) {
                    Color.black
                    ForEach(0..<colors.count) {i in
                        RoundedRectangle(cornerSize: CGSize(width: 30, height: 30))
                            .fill(colors[i])
                            .frame(width: 300, height: 300 )
                            .offset(x: 0, y: CGFloat(i) * 200)
                    }
                }
                .frame(height: CGFloat(200*(colors.count-1))+300)
        }
    }
}