Unnecessary white area at ScrollView bottom beyond its child content, in SwiftUI?

133 views Asked by At

I have a scroll view just like that.

public var body: some View {
        ScrollView {
            ZStack {
                VStack(spacing: 0) {
                    BannerView
                        .frame(height: UIScreen.main.bounds.height * 0.30)
                    SignInContent
                }
            }
        }
        .ignoresSafeArea(.all)
}

Before adding the scrollview, everything was fine except the screen is not able to scroll. But after I put inside a scrollview. The white area appear. Spacer() can't help pushing from inside to bottom. Below screenshot, ZStack is highlighted which is inside the scrollview. I also find a way to change background color of scrollview but can't. The only solution i found yet is to add .padding(.bottom) to the lowest view of SignInContent but I don't think it's a proper way.

enter image description here

1

There are 1 answers

7
Benzy Neez On BEST ANSWER

You have set the height of BannerView to 0.3 of the screen height. So I guess SignInContent has the black background. But if the height of SignInContent is not as much as 0.7 of the screen height then the background will run out.

A Spacer inside a ScrollView will have no effect, so maybe this is why the height of SignInContent is less than it was before the ScrollView was put around it. Even setting frame(maxHeight: .infinity) will have no effect.

To fix, you could move the background to the ScrollView:

ScrollView {
    // content as before
}
.background(.black)

Alternatively, you could set the minimum height of SignInContent to the remainder of the screen height. Here, it would be better to use a GeometryReader to read the height of the screen, instead of using UIScreen.main.bounds, which is deprecated. However, if the height is increased after the background is applied, then the background won't grow. So you need to do it the other way around and apply the background after increasing the height:

GeometryReader { proxy in
    ScrollView {
        ZStack {
            VStack(spacing: 0) {
                BannerView
                    .frame(height: proxy.size.height * 0.30)
                SignInContent
                    .frame(minHeight: proxy.size.height * 0.7, alignment: .top)
                    .background(.black)
            }
        }
    }
}
.ignoresSafeArea(.all)

You wouldn't have to apply the background again if SignInContent was implemented as a ZStack with the background color as one of the layers:

var signInContent: some View {
    ZStack(alignment: .top) {
        Color.black

        // The other content here
    }
    .frame(maxWidth: .infinity)
}

var body: some View {
    GeometryReader { proxy in
        ScrollView {

            // somewhere inside ScrollView
            signInContent
                .frame(minHeight: proxy.size.height * 0.7)
        }
    }
    .ignoresSafeArea(.all)
}