Make ScrollView content fill its parent in SwiftUI

Viewed 38206

I'd love to build a scrolling screen, so I wanted to embed it ScrollView. But I am not able to achieve it the view just shrinks to its compressed size. Let's say that I want the ScrollView to scroll vertically so I'd love the content to match scrollView's width. So I use such preview:

struct ScrollSubview_Previews : PreviewProvider {
    static var previews: some View {
        func textfield() -> some View {
            TextField(.constant("Text")).background(Color.red)
        }

        return Group {
            textfield()
            ScrollView {
                textfield()
            }
        }
    }
}

But it ends with result like this:

enter image description here

7 Answers

A simple way for you, using frame(maxWidth: .infinity)

    ScrollView(.vertical) {
        VStack {
           ForEach(0..<100) {
              Text("Item \($0)")
          }
       }
       .frame(maxWidth: .infinity)
   }

Actually you don't need GeometryReader anymore. ScrollView has been refactored in Xcode beta 3. Now you can declare that you have a .horizontal or .vertical ScrollView. This makes the ScrollView behave like it should, like any normal View protocol.

Ex:

ScrollView(.horizontal, showsIndicators: false) {
    HStack {
        ForEach((1...10).reversed()) {
            AnyViewYouWant(number: $0)
        }
    }
}

This will result in a view with the width of its parent scrolling horizontally. The height will be defined by the ScrollView's subviews height.

Here is a trick: introduce a HStack that only has one Spacer:

return Group {
        HStack {
            Spacer()
        }
        textfield()
        ScrollView {
            textfield()
        }
    }

It's a known issue existing also in beta 2 - check the Apple's Xcode 11 release notes here ⬇️ https://developer.apple.com/documentation/xcode_release_notes/xcode_11_beta_2_release_notes.

The workaround mentioned by Apple themselves is to set fixed frame for ScrollView inside element. In that case I suggest to use GeometryReader for fix screen width, height is automatically fit to content.

For example if you need to fit the ScrollView's content to screen width you can something like:

return GeometryReader { geometry in
     Group {
         self.textfield()
         ScrollView {
             self.textfield()
                 .frame(width: geometry.size.width)
         }
     }
 }
  • You can also done this using extra HStack and space.

    ScrollView(.vertical) {
        HStack {
            VStack {
                 ForEach(0..<100) {
                    Text("Item \($0)")
                 }
             }
             Spacer()
         }
    }
    

Scroll view content will expand to available size.

GeometryReader { geo in
            ScrollView(.vertical) {
                YourView().frame(
                    minWidth: geo.size.width,
                    minHeight: geo.size.height
                )
            }
        }

PreviewProvider is just about your Canvas (rendering view).

if you want to place text into ScrollView you should create your View

struct MyViewWithScroll : View {
    var body: some View {
        ScrollView {
            Text("Placeholder")
        }
    }
}

And after that, render your MyViewWithScroll in Canvas (window with iPhone from the right side of code editor)

#if DEBUG
struct MyViewWithScroll_Previews : PreviewProvider {
    static var previews: some View {
        MyViewWithScroll()
    }
}
#endif
Related