Vincent
Vincent

Reputation: 83

How do I retrieve the height of a specific view?

Let's say I have a circle that I want to change the radius of upon interaction. I want the radius to be defined as a percentage of a view height. I have the following:

struct ButtonView: View {

    @State private var radius: CGFloat = 0.1 * geometry.size.height

    var body: some View {
        GeometryReader { geometry in
            Button(action: {
                withAnimation(.easeIn) { () -> Result in
                    self.radius = 0.1 * geometry.size.height
                }
            }) {
                Circle().frame(width: self.radius, height: self.radius)
            }
            .onLongPressGesture(minimumDuration: 0, maximumDistance: 0, pressing: { (true) in
                self.radius = 0.1 * geometry.size.height - 10
            }) {}
        }
    }
}

My problem is that I cannot reference 'geometry.size.height' in the variable statement because it is not nested in the GeometryReader. I've tried using 'UIScreen.main.bounds.width,' but this gives the height of the entire screen. In my circumstance, I'm interested in attaining the height of the view above a tab bar, as ButtonView is nested within one.

Upvotes: 2

Views: 102

Answers (1)

Rob Napier
Rob Napier

Reputation: 299325

A State variable's initial value can't be based on a specific layout. When the struct is created, it doesn't know what the layout is. But you're free to use the GeometryReader's proxy during layout. For example, this scales the circle between 10% and 50% of the view's height. Note the use of maxHeight here in the frame.

struct ButtonView: View {

    @State private var scale: CGFloat = 0.1

    var body: some View {
        GeometryReader { proxy in
            Button(action: { self.scale = (self.scale == 0.1) ? 0.5 : 0.1 }) {
                Circle()
            }
            .frame(maxHeight: proxy.size.height * self.scale)
        }
    }
}

If you want to capture the information into a State variable on the first appearance, then you can do that in an onAppear block.

struct ButtonView: View {

    @State private var radius: CGFloat = 0.0

    var body: some View {
        GeometryReader { proxy in
            Button(action: { self.radius = 0.5 * proxy.size.height }) {
                Circle()
            }
            .frame(maxHeight: self.radius)
            .onAppear { self.radius = 0.1 * proxy.size.height}
        }
    }

Upvotes: 2

Related Questions