3

Edit:

It was confirmed to be an Apple bug. It's now fixed on macOS Monterey


It seems to me that reading frames through GeometryReader is broken on macOS.

Apparently when you read a frame in local or named coordinate space, returned frame is in "SwiftUI coordinate space" where the (0,0) point is in the upper-left corner.

However, when you read a frame in a global space, returned frame is in the "native macOS space" where the (0,0) is in the bottom-left corner.

Is this behavior documented anywhere or is it a bug? I'm trying to figure out if I'm missing something here.

My sample code:

struct ContentView: View {
var body: some View {
    ZStack(alignment: .bottom) {
        Color.blue
            .frame(width: 100, height: 150)


        Color.red
            .frame(width: 20, height: 60)
            .background(
                GeometryReader { geo -> Color in
                    let g = geo.frame(in: .global)
                    let s = geo.frame(in: .named("stack"))
                    print("Global: \(g) | Stack: \(s)")

                    return Color.purple
                }
            )
        .padding(.bottom, 5)
    }
    .coordinateSpace(name: "stack")
    .padding(40)
    .background(Color.pink)
}

Output:

Global: (80.0, 45.0, 20.0, 60.0) | Stack: (40.0, 85.0, 20.0, 60.0)

enter image description here

msmialko
  • 1,439
  • 2
  • 20
  • 35
  • Known and documented. See [https://stackoverflow.com/questions/21751105/mac-os-x-convert-between-nsview-coordinates-and-global-screen-coordinates](https://stackoverflow.com/questions/21751105/mac-os-x-convert-between-nsview-coordinates-and-global-screen-coordinates) & from the [Apple Developer Archives](https://developer.apple.com/library/archive/documentation/General/Conceptual/Devpedia-CocoaApp/CoordinateSystem.html). – Yrb Nov 27 '20 at 14:38
  • 1
    @Yrb I know that macOS is using a different coordinate system than iOS. And it all make sense when you're using pure Cocoa. What I found confusing is that SwiftUI returns frames in *both* ways. When asked for "global" frame, it is in the different coordinate system than the "local" frame. This is especially problematic as SwiftUI is a multi-platform framework so its behavior should be more or less the same on all the platforms. – msmialko Nov 27 '20 at 14:45
  • @msmialko Agreed. I'd expect "Global" to reference a window and some other term for screen coordinates. Or for docs to say you'd need to setup a named coordinate space for each window in your App struct. – Ryan Jan 21 '21 at 07:22

1 Answers1

0

I gotcha. I misread what you wrote. I spent some time going down this rabbit hole, and found no clear answer. No one is talking about local versus global coordinate spaces. As a test on .frame, I modified your GeometryReader like this:

GeometryReader { geo -> Color in
                        let g = geo.frame(in: .global)
                        let gX = g.minX
                        let gY = g.minY
                        let s = geo.frame(in: .named("stack"))
                        print("Global: \(g), minX: \(gX), minY: \(gY) | Stack: \(s)")

and the output ended up being:

Global: (80.0, 45.0, 20.0, 60.0), minX: 80.0, minY: 45.0 | Stack: (40.0, 85.0, 20.0, 60.0)

So, while I can't answer your question as to what Apple intended, clearly the Global coordinate system is rotated, and it is not a bug in .frame switching x for y in a global space. Yet something else that is undocumented.

Yrb
  • 8,103
  • 2
  • 14
  • 44