0

I have a view that needs to know its parent's size when being initalized. Here's a simplified example of the code, where the Text displays the size provided by the GeometryReader.

    struct ContentView: View {
        var body: some View {
            GeometryReader { proxy in
                ZStack {
                    Rectangle()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .foregroundColor(.blue)
                    Text("Size: \(proxy.size.width) x \(proxy.size.height)")
                }
            }
        }
}

When I run this code on iOS, the body is updated once and the size is correct from the start. When I run this code on macOS, the body is updated four times. The first three times the size is wrong and only the fourth time the size is correct.

In this example it does not matter all that much, but in my app the layout and animations depend on knowing the correct size of the parent view from the start.

Any ideas how I can make sure the Text will only be initalized when the final size is available on macOS?

viedev
  • 869
  • 1
  • 6
  • 16
  • Different windows systems, different state restoration, etc... we should not rely on that or make any expectations. – Asperi Jun 21 '22 at 17:47
  • How do you know that body is updated 4 times ? i show only one update – Ptit Xav Jun 21 '22 at 18:44
  • You can either set a breakpoint or add `.onAppear` and `.onChange(of: proxy.size)` modifiers and print to the log. – viedev Jun 21 '22 at 18:56

1 Answers1

0

After fiddling with this for a while, I tried using the custom geometry reader described in this answer by Asperi: https://stackoverflow.com/a/69931609/14542345 Using this CustomGeometryReaderView will provide the correct size on macOS at once, which is great and it also works on iOS.

Unfortunately I ran into problems when animating size changes. Since the size seems to be provided later than with a regular GeometryReader some animations are delayed (e.g. collapsing sidebar on macOS and the view is still animating when the sidebar is already gone).

The strange solution

The solution (and I honestly don't understand why this works) is wrapping the regular GeometryReader in CustomGeometryReaderView but only using the values from the regular GeometryReader:

CustomGeometryReaderView { size in
       GeometryReader { proxy in
             ZStack {
                  Rectangle()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .foregroundColor(.blue)
                  Text("Size: \(proxy.size.width) x \(proxy.size.height)")
              }
       }
}

The size from the custom reader is never used, but somehow it causes the regular GeometryReader to only send the size once .onAppear and not again three times .onChange.

viedev
  • 869
  • 1
  • 6
  • 16