14

I'm trying to center a bunch of views in a VStack within a ScrollView in SwiftUI. To simplify things, I'm just trying to get it to work with a single Text view. Here's what I've come up with so far:

var body: some View {
  ScrollView(alwaysBounceVertical: true){
    HStack(alignment: .center) {
      Spacer()
      Text("This Is a Test")
      Spacer()
    } //HStack
    .background(Color.green)
  } //ScrollView
  .background(Color.gray)
}

This results in this:

enter image description here

I want the text to be in the middle like this:

enter image description here

So the HStack should be full-width and the Text should be centered within it. It seems like this should be easy, but I don't get what I'm doing wrong. :)

1
  • 1
    I'm using Xcode beta 5 and your code is working fine with me. Which Xcode are you using ? Because In beta 5, ScrollView doesn't have alwaysBounceVertical Modifier. Commented Oct 1, 2019 at 15:52

4 Answers 4

21

Using GeometryReader, you can get information about the size of the containing view and use that to size your view.

    var body: some View {
        GeometryReader { geometry in                <--- Added
            ScrollView(alwaysBounceVertical: true){
                HStack(alignment: .center) {
                    Spacer()
                    Text("This Is a Test")
                    Spacer()
                } //HStack
                .frame(width: geometry.size.width)  <--- Added
                .background(Color.green)
            } //ScrollView
        .background(Color.gray)
    }
}

edit: after looking into this more, it seems that part of the problem is that you are using a ScrollView. If you remove that parent, the spacers in the HStack will automatically cause stretching to fill the view. I'm guessing the automatic stretching doesn't happen in ScrollViews because there's no finite limit to how big it can be, how much would it stretch? (because a ScrollView can scroll in any direction)

Sign up to request clarification or add additional context in comments.

1 Comment

This sounds like a good explanation. But should it not be possible maybe to limit one scrolling direction for a scrollview to fix such issues? 🤔
4

This seems to be a bug in Xcode 11.0 beta, ScrollView content wouldn't fill the scroll view. If you replace the ScrollView with a List it will work as expected. But if you have to use a scroll view, one workaround is to fix the scroll view's content width.

So your code will look something like this:

ScrollView(alwaysBounceVertical: true) {
  HStack(alignment: .center) {
    Spacer()
    Text("This Is a Test")
    Spacer()
  } // HStack
  .frame(width: UIScreen.main.bounds.width) // set a fixed width
  .background(Color.green)
} // ScrollView
.background(Color.gray)

Result:

enter image description here

3 Comments

Please use GeometryReader rather the UIScreen bounds
@MatteoPacini Why is that? Is it because it won't work when the device is rotated?
This solution works, but now I'm just debating between setting the .frame and using GeometryReady. Thank you!
4

You should use the modifier frame and set its maxWidth: .infinity. So it tells its parent: "the wider, the better" :)

var body: some View {
  ScrollView(.vertical, showsIndicators: true){
    HStack(alignment: .center) {
      Spacer()
      Text("This Is a Test")
        .frame(maxWidth: .infinity) // <- this
      Spacer()
    } //HStack
    .background(Color.green)
  } //ScrollView
  .background(Color.gray)
}

And this works regardless its parent. Scrollview or whatever View it's set in.

Paul is doing a great job clarifying it to all of us here:

https://www.hackingwithswift.com/quick-start/swiftui/how-to-give-a-view-a-custom-frame

Answer compatible with Xcode 12.1 (12A7403) I hope this helps 👍 dsa

2 Comments

There isn't constructor method with alwaysBounceVertical for ScrollView.
@ErkamKUCET fixed
3

Depending on what you're doing, ViewThatFits might be a good solution for this. For my use case, I needed a horizontal ScrollView if the content was too wide, but an HStack was sufficient otherwise.

This works for me:

var body: some View {
  ViewThatFits {
    HStack(alignment: .center) {
      Spacer()
      Text("This Is a Test")
      Spacer()
    } //HStack
    .background(Color.green)

    ScrollView(alwaysBounceVertical: true){
      HStack(alignment: .center) {
        Spacer()
        Text("This Is a Test")
        Spacer()
      } //HStack
      .background(Color.green)
    } //ScrollView
    .background(Color.gray)
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.