Macos 如何在SwiftUI中获取窗口坐标?

Macos 如何在SwiftUI中获取窗口坐标?,macos,swiftui,Macos,Swiftui,我想制作一个视差背景视图,当窗口在屏幕上移动时,UI后面的图像几乎保持静止。要在macOS上执行此操作,我需要获取窗口的坐标如何获取窗口的坐标? 我这样问是因为我找不到任何地方说明如何做到这一点: 谷歌搜索帮助我找到以下结果: , 苹果开发者文档: -我曾希望这将包含一个API,以提供系统坐标空间中的框架,但似乎所有方法都只包含窗口坐标中的引用 -我本来希望苹果会在这篇文章中提到窗口,但除了说你可以在Xcode预览窗格中预览主窗口的内容之外,根本没有提到 无果搜索: 其他问题: -

我想制作一个视差背景视图,当窗口在屏幕上移动时,UI后面的图像几乎保持静止。要在macOS上执行此操作,我需要获取窗口的坐标如何获取窗口的坐标?


我这样问是因为我找不到任何地方说明如何做到这一点:

  • 谷歌搜索帮助我找到以下结果:

    • ,
  • 苹果开发者文档:

    • -我曾希望这将包含一个API,以提供系统坐标空间中的框架,但似乎所有方法都只包含窗口坐标中的引用
    • -我本来希望苹果会在这篇文章中提到窗口,但除了说你可以在Xcode预览窗格中预览主窗口的内容之外,根本没有提到
    • 无果搜索:
  • 其他问题:

    • -我很乐观,这将有一个答案,它将为我提供一个快速UI API来访问窗口,但它使用一个垫片来访问AppKit窗口表示
    • -与上述问题类似,但这一次的答案只是阅读内容视图的框架,该框架始终具有
      (0,0)
      原点
    • -我希望这个答案能让我知道如何将
      GeometryReader
      给出的坐标转换为屏幕坐标,但不幸的是,坐标再次被限制在窗口内
  • 网上其他地方:

    • 顺便说一句,我希望这能给我一些在Mac上使用SwiftUI的技巧,比如与windows交互,因为大多数教程都关注iOS/iPadOS。不幸的是,尽管它有很多关于SwiftUI如何与windows协同工作的好信息,但它没有关于与这些窗口交互或解析这些窗口本身的信息
    • by-希望在屏幕上显示窗口布局,但这是全屏幕iOS应用程序的全部
    • by-希望能有一个示例来说明如何获取窗口的位置,但在列出的示例中似乎根本没有提到窗口
正如我所列出的,我发现所有这些要么与我的问题无关,要么只引用窗口中的坐标,而不是屏幕中窗口的坐标。有些人提到了使用AppKit的方法,但如果可能的话,我想避免使用AppKit

我得到的最接近的结果是尝试使用
GeometryReader
如下:

public struct ParallaxBackground<Background: View>: View {
    var background: Background

    @Environment(\.windowFrame)
    var windowFrame: CGRect

    public var body: some View {
        background
            .offset(x: windowFrame.minX / 10,
                    y: windowFrame.minY / 10)
    }
}
GeometryReader{geometry中的几何体
文本(逐字:\(geometry.frame(in:.global)))
}
但原点始终是
(0,0)
,尽管在我调整窗口时大小确实发生了变化


我所设想的可能是这样的:

public struct ParallaxBackground<Background: View>: View {
    var background: Background

    @Environment(\.windowFrame)
    var windowFrame: CGRect

    public var body: some View {
        background
            .offset(x: windowFrame.minX / 10,
                    y: windowFrame.minY / 10)
    }
}
公共结构视差背景:视图{
背景:背景
@环境(\.windowFrame)
var windowFrame:CGRect
公共机构:一些看法{
背景
.偏移量(x:windowFrame.minX/10,
y:windowFrame.minY/10)
}
}

但是窗框不是真的;它不指向
EnvironmentValues
上的任何键路径。我找不到在哪里可以得到这样的值。

如果您想要窗框:

SceneDelegate跟踪所有窗口,因此您可以使用它创建一个
EnvironmentObject
,并引用它们的帧,然后将其传递给视图。更新委托方法中的环境对象值:
func-windowScene(windowScene:UIWindowScene,diddupdate-previouscoordinarespace:uicoordinarespace,…

如果它是一个单窗口应用程序,则更直接。您可以在视图中使用UIScreen.main.bounds(如果是全屏)或计算变量:

var frame:CGRect{(UIApplication.shared.connectedScenes.first?.delegate as?SceneDelegate)?.window?.frame???.zero}

但是,如果要在窗口中查找视图的框架,请尝试以下操作:

struct ContentView: View {
  @State var frame: CGRect = .zero

  var orientationChangedPublisher = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)

  var body: some View {
    VStack {
      Text("text frame georeader \(frame.debugDescription)")
    }
    .background(GeometryReader { geometry in
      Color.clear // .edgesIgnoringSafeArea(.all) // may need depending
        .onReceive(self.orientationChangedPublisher.removeDuplicates()) { _ in
          self.frame = geometry.frame(in: .global)
      }
    })
  }
} 
尽管如此,通常你不需要一个绝对的框架。对齐向导让你相对地放置物体

//对于macOS应用程序,使用帧更改通知并作为环境对象传递到SwiftUI视图

class WindowInfo: ObservableObject {
  @Published var frame: CGRect = .zero
}

@NSApplicationMain

class AppDelegate: NSObject, NSApplicationDelegate {

  var window: NSWindow!

  let windowInfo = WindowInfo()

  func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
      .environmentObject(windowInfo)

    // Create the window and set the content view. 
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")
    window.contentView = NSHostingView(rootView: contentView)
    window.contentView?.postsFrameChangedNotifications = true
    window.makeKeyAndOrderFront(nil)

    NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: nil, queue: nil) { (notification) in
      self.windowInfo.frame = self.window.frame
    }
  }

正如我在问题顶部及其标签中所说的,这是针对macOS应用程序的。虽然在iOS中考虑这一点很简单,但你能将其从UIKit转换为AppKit吗?我希望你可以用NSView.frameDidChangeNotification替换方向更改通知,但它不起作用。然而,在一个循环中,你仍然可以l使用它获取帧信息并将其传递给SwiftUI视图(更新的答案)。