Search code examples
iosswiftswiftuiscrollviewlazyvstack

How to align ScrollView content to top when both axes are used?


Here's a simple example:

struct Example: View {
    var body: some View {
        ScrollView([.horizontal, .vertical], showsIndicators: false, content: {
            LazyVStack(content: {
                ForEach(1...10, id: \.self) { count in
                    Text("Item \(count)")
                }
            })
        })
    }
}

The problem is that when both axes are used ([.horizontal, .vertical]), ScrollView automatically centers any content inside vertically and horizontally. I have a big data table in the ScrollView, and I need it to be aligned to top instead but I couldn't figure out how to do this. Usual stuff with Vstacks and Spacers doesn't work here at all.


Solution

  • I made an example, with a Slider so you can interactively test it.

    This works by making sure the content within the ScrollView is at least as high as the ScrollView itself. This leads to the content filling the whole vertical space, so it will start at the top.

    Code:

    struct Example: View {
        @State private var count: Double = 10
    
        var body: some View {
            VStack {
                GeometryReader { geo in
                    ScrollView([.horizontal, .vertical], showsIndicators: false, content: {
                        VStack(spacing: 0) {
                            LazyVStack {
                                ForEach(1 ... Int(count), id: \.self) { count in
                                    Text("Item \(count)")
                                }
                            }
    
                            Spacer(minLength: 0)
                        }
                        .frame(width: geo.size.width)
                        .frame(minHeight: geo.size.height)
                    })
                }
    
                Slider(value: $count, in: 10 ... 100)
            }
        }
    }
    

    In some cases you may need to use .frame(minWidth: geo.size.width) rather than just width. This can be in the same line as the minHeight.