最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

geometryreader - SwiftUI onGeometryChange modifier with frame - Stack Overflow

programmeradmin1浏览0评论

What's wrong with the following code that the viewSize height remains zero despite having a frame modifier set to height 60?


struct TestGeometryModifierView: View {
    @State var viewSize:CGSize = .zero
    
    var body: some View {
        Color.red
            .onGeometryChange(for: CGSize.self) { proxy in
                proxy.size
            } action: { newValue in
                viewSize = newValue
                print("View Size \(newValue)")
            }
            .frame(height:viewSize.height)
    }
    
}

#Preview {
    TestGeometryModifierView()
        .frame(height:60)
}

The print statement on console shows only one line. I expect it to change when frame height is set on the view.

View Size (402.0, 0.0)

What's wrong with the following code that the viewSize height remains zero despite having a frame modifier set to height 60?


struct TestGeometryModifierView: View {
    @State var viewSize:CGSize = .zero
    
    var body: some View {
        Color.red
            .onGeometryChange(for: CGSize.self) { proxy in
                proxy.size
            } action: { newValue in
                viewSize = newValue
                print("View Size \(newValue)")
            }
            .frame(height:viewSize.height)
    }
    
}

#Preview {
    TestGeometryModifierView()
        .frame(height:60)
}

The print statement on console shows only one line. I expect it to change when frame height is set on the view.

View Size (402.0, 0.0)
Share Improve this question edited Mar 28 at 17:54 HangarRash 15.1k5 gold badges20 silver badges55 bronze badges asked Mar 28 at 11:20 Deepak SharmaDeepak Sharma 6,63110 gold badges66 silver badges161 bronze badges 6
  • 1 Remember how I said frame isn't actually directly changing the size of the view it modifies? It merely adds an invisible frame around the view. So here you have some red color in a .frame(height:viewSize.height), which is in another .frame(height:60). The frame on the inside is fixed. It doesn't care about how big the frame on the outside is. – Sweeper Commented Mar 28 at 12:52
  • 1 In terms of size proposals, the frame on the outside proposes a height of 60 to the frame on the inside. The frame on the inside ignores this proposal and proposes a height of 0 to the red color. Do you have some ultimate goal that you are trying to achieve? At its current state I don't think this is a very useful question. – Sweeper Commented Mar 28 at 12:56
  • What is the point of .frame(height:viewSize.height)? For views that uses the full height of the size proposal (e.g. Color), this will always create a 0-height view. For views that ignore the height of the size proposal, the height of the frame will always be the same as the height of the view anyway, so the frame modifier is redundant. – Sweeper Commented Mar 28 at 13:06
  • @Sweeper I understand your point. The code I posted is merely sample code to reproduce the issue. I was trying to avoid using GeometryReader as I read onGeometryChange can for all intents and purposes replace it. I have a subview in a ScrollView whose height I need to set to height of superview and that is why I was playing around with viewSize to grab how much space is available. – Deepak Sharma Commented Mar 28 at 13:28
  • @Sweeper I shall post a new question which is much more useful and place the link here. – Deepak Sharma Commented Mar 28 at 13:30
 |  Show 1 more comment

1 Answer 1

Reset to default 2

A Color is greedy and consumes as much space as possible. However, you are also setting the height using .frame and this height is initialized to zero. So on initial show, the width is as wide as possible, but the height is zero.

The height you are measuring using .onGeometryChange is therefore zero, in other words, the value that the state variable was initialized with. Since the size does not change, .onGeometryChange is not triggered again.

The height of 60 that you are setting on the surrounding view has no impact on the view that you are measuring with .onGeometryChange. So this additional .frame modifier does not cause .onGeometryChange to trigger.


If you are trying to measure the full size available then you could use an optional for the state variable instead:

@State var viewSize: CGSize?
Color.red
    .onGeometryChange(for: CGSize.self) { proxy in
        // ... as before
    }
    .frame(height: viewSize?.height)

The modifier .onGeometryChange is still only triggered once because the initial size is the same as the size that is set by the .frame modifier. But now, the state variable measures a useful value:

View Size (393.0, 60.0)

发布评论

评论列表(0)

  1. 暂无评论