2

I would like to have a VStack with a single view with fixed height on top, and the rest of the VStack taken up by a ScrollView. The code I am using right now to test this out is shown below. That works just fine when I use 3 Text views and the ScrollView, the 3 Text views show on top, with the ScrollView taking up the rest of the space:

enter image description here

But when I remove one of the 3 text views, the ScrollView fills the whole screen, covering the Text views:

enter image description here

How do I make it work with one view on top?

struct ContentView: View {
    var body: some View {
        return VStack {
            Text("First Text")
            .background(Color(red:0.5, green:0, blue:0))
            Text("Second")
            Text("Third")
            ScrollView {
                VStack(spacing:0) {
                    Text("Hello")
                    Text("World")
                }
            }
            .frame(maxWidth:.infinity)
//            .edgesIgnoringSafeArea(.all)
            .background(Color(red:0, green:0.5, blue:0))
        }
        .edgesIgnoringSafeArea(.all)
        .frame(maxWidth:.infinity, maxHeight:.infinity)
    }
}

2 Answers 2

1

I found a satisfactory solution. The problem was caused by the .edgesIgnoringSafeArea of the encompassing VStack. I want to use all the space available, and not have the default empty space at the top. Apparently that messes up the layout of the views inside the VStack in incomprehensible ways.

Instead of placing the text views inside the VStack, I now place them explicitly in the safe area of the scrollview, and that seems to work:

enter image description here

The scrollview still fills the whole screen, but the Text views are now on top of it, and in its safe area, and that works fine for me.

Here is the code:

var body: some View {
    return VStack(spacing:0) {
        ScrollView {
            VStack {
                Text("Hello")
                Text("World")
            }
        }
        .frame(maxWidth: .infinity)
        .background(Color(red:0, green:0.5, blue:0))
        .safeAreaInset(edge: .top) {
            VStack {
                Text("First")
                    .frame(height:40)
                    .background(Color(red:0.5, green:0, blue:0))
                Text("Second")
                // Text("Third")
            }
        }
    }
    .frame(maxWidth:.infinity, maxHeight:.infinity)
    .edgesIgnoringSafeArea(.all)
}
Sign up to request clarification or add additional context in comments.

Comments

0

It seems this is a weird bug in WatchOS. You can report it here. For now, you can fix it by adding 11pt spacing to the top VStack and putting the text items in their own nested VStack.

var body: some View {
    return VStack(spacing: 11) {
        VStack {
            Text("First Text")
            .background(Color(red:0.5, green:0, blue:0))
            Text("Second")
            Text("Third")
        }
        ScrollView {
            VStack(spacing:0) {
                Text("Hello")
                Text("World")
            }
        }
        .frame(maxWidth:.infinity)
    //            .edgesIgnoringSafeArea(.all)
        .background(Color(red:0, green:0.5, blue:0))
    }
    .edgesIgnoringSafeArea(.all)
    .frame(maxWidth:.infinity, maxHeight:.infinity)
}

1 Comment

Thanks for the answer, but it does not actually help much. It still fails when I have just one Text view in the VStack. The first three views are just for testing purposes, in the final application their is only one top view, and it is going to be a different view, likely a HStack. I could not get it to work, and made a bare bones example to show the problem.

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.