26

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

olejnjak
  • 1,163
  • 1
  • 9
  • 23
  • Possible duplicate of [Make a VStack fill the width of the screen in SwiftUI](https://stackoverflow.com/questions/56487323/make-a-vstack-fill-the-width-of-the-screen-in-swiftui) – Jake Jun 07 '19 at 07:27

7 Answers7

26

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

ScrollView(.vertical) {
    VStack {
        ForEach(0..<100) {
            Text("Item \($0)")
        }
    }
    .frame(maxWidth: .infinity)
}
Jenea Vranceanu
  • 4,530
  • 2
  • 18
  • 34
Hoang Nguyen
  • 344
  • 3
  • 4
11

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

return Group {
        HStack {
            Spacer()
        }
        textfield()
        ScrollView {
            textfield()
        }
    }
ielyamani
  • 17,807
  • 10
  • 55
  • 90
9

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)
         }
     }
 }
xxcat
  • 127
  • 7
9

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.

shim
  • 9,289
  • 12
  • 69
  • 108
  • 18
    This answer is completely irrelevant to the question. He didn't ask about the direction of the scroll view. – Peter Schorn Sep 20 '20 at 04:26
  • 1
    @PeterSchorn this is the way to fill the super view at the moment. Before it, you had to use geometry reader to know the correct space since we didn't have a .vertical or .horizontal param, that happened during the beta. Now you can add a ScrollView just like any view. I hope you understood the context. – Leonel Menezes Morato Lima Oct 23 '20 at 13:51
  • @PeterSchorn before it, the ScrollView would resize it's subviews, not showing the desired content. – Leonel Menezes Morato Lima Oct 23 '20 at 13:53
  • 1
    I think there is a glitch or misunderstanding somewhere in here. My scroll view is taking the size of the screen. However 'custom views, set to use all available space' inside the scroll are not stretching to fill the content of the scroll view. I know they should. And they do if you play with a typical Text for example... – Klajd Deda Jan 02 '21 at 18:50
  • @LeonelMenezesMoratoLima this answer is still wrong. – Claus Jørgensen Dec 03 '21 at 09:54
4

Scroll view content will expand to available size.

GeometryReader { geo in
            ScrollView(.vertical) {
                YourView().frame(
                    minWidth: geo.size.width,
                    minHeight: geo.size.height
                )
            }
        }
2
  • You can also done this using extra HStack and space.

    ScrollView(.vertical) {
        HStack {
            VStack {
                 ForEach(0..<100) {
                    Text("Item \($0)")
                 }
             }
             Spacer()
         }
    }
    
Amisha Italiya
  • 168
  • 1
  • 8
-4

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
Argas
  • 1,427
  • 1
  • 10
  • 12