Linas
Linas

Reputation: 75

SWIFTUI How to capture VStack height with geometry (after the VStack was displayed)?

I'd like to ask you some help. I'm trying to capture VStack height using geometry and then based on that VStack height value, calculate its child element's height (inside VStack).

Image of my current view of VStack

I used .frame outside of VStack to fill the whole screen. Then I used .border to visually check if it actually fills the screen (it works fine)

.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.topLeading)

The problem can be seen inside the VStack, the height is displayed as GCFloat 734. Even though the border size is a lot bigger.

struct BodyView: View {
    @State var stackHeight : CGFloat = 0

    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("VStack size: \(self.stackHeight)")
                    .bold()
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(.horizontal)
                    .background(Color.green)

            }
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.topLeading)
            .onAppear{
                self.stackHeight = geometry.size.height
            }
            .border(Color.purple, width: 5)
        }
    }
}

struct BodyView_Previews: PreviewProvider {
    static var previews: some View {
        BodyView()
    }
}

How could I capture the actual size of the VStack when it finishes loading?
When I trigger (onAppear) the VStack height appears correct, however I need it to be captured instantly.

Upvotes: 2

Views: 5104

Answers (2)

Aaban Tariq Murtaza
Aaban Tariq Murtaza

Reputation: 1252

You need to use geometry reader with background to get right height.

VStack {
    yourContent
}
.background {
   GeometryReader { reader in
       Color.clear
       .onChange(of: reader.size.height) { newVal in
            heightStateVariable = newVal
       }
       .onAppear {
            heightStateVariable = reader.size.height
       }
   }
}

In SwiftUI .background content takes space as per VStack content (upon which background modifier applied - some exceptions are there)

Upvotes: 0

nteissler
nteissler

Reputation: 1581

If I understand your questions, you're very close — you just need to use to GeometryProxy type:

import SwiftUI

struct BodyView: View {

    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("VStack size: \(geometry.size.height)") // no need for state var anymore
                    .bold()
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .padding(.horizontal)
                    .background(Color.green)
            }
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.topLeading)
            .border(Color.purple, width: 5)
        }
    }
}

struct BodyView_Previews: PreviewProvider {
    static var previews: some View {
        BodyView()
    }
}

A GeometryReader will lay itself out again if its size changes.

Upvotes: 2

Related Questions