Soid
Soid

Reputation: 2881

Window position for SwiftUI hosted view in MacOS Storyboard app

I'm trying new create some new windows using SwiftUI in my older MacOS app that uses Storyboards. It works pretty well, however, I'm unable to position the window on the screen. It seems there is some kind of conflict in coordinates system.

If I just use window.center() then it positions the top left corner to the center horizontally (not the center of the window is in the center of the screen, but the corner itself is in the center), and at the top vertically (right below menu bar).

If I use window.setFrameTopLeftPoint(.init(x: 0, y: 0)) then it sets the bottom left point instead. It seems some kind of reverted coordinate system? How do I make it work with AppKit?

Here is my SwiftUI window creation code (runs from Storyboard created window):

@IBAction func onButtonClicked(_ sender: Any) {
    let window = NSWindow(
        contentRect: .init(origin: .zero, size: .init(width: 400, height: 400)),
        styleMask: [.titled, .closable],
        backing: .buffered,
        defer: false
    )

    window.title = "Child SwiftUI Window"
    // window.center()
    window.setFrameTopLeftPoint(.init(x: 100, y: 100))

    // Use the class property instead of local variable
    let windowController = NSWindowController(window: window)
    windowController.contentViewController = ChildHostingController()!
    windowController.showWindow(nil)
}

SwiftUI view + hosting controller:

class ChildHostingController: NSHostingController<SwiftUITestView> {
    required init?(coder: NSCoder) {
        super.init(coder: coder,
                   rootView: SwiftUITestView())
    }
    required init?() {
        super.init(rootView: SwiftUITestView())
    }
}

struct SwiftUITestView: View {
    var body: some View {
        VStack { 
            Spacer()
            Text("This is a child window from SwiftUI")
            Spacer()
        }
        .padding(20)
        .frame(width: 400, height: 400)
    }
}

Upvotes: 0

Views: 40

Answers (1)

Sweeper
Sweeper

Reputation: 273540

I suspect this is related to how the hosting controller determines the size of the SwiftUI view, and the window receives an incorrect size when it tries to position itself on centered the screen.

By trial and error, I found that using .preferredContentSize as the sizingOptions fixes this. You can set it in the initialiser of ChildHostingController

required init?() {
    super.init(rootView: SwiftUITestView())
    sizingOptions = .preferredContentSize
}

Then calling window.center() like you did in your code works correctly.

Alternatively, you can also set the size of the hosting controller's view directly, but only if you know the size of the SwiftUI view beforehand.

super.init(rootView: SwiftUITestView())
view.setFrameSize(.init(width: 400, height: 400))

Upvotes: 1

Related Questions