我想制作一个视差背景视图,其中当窗口在屏幕上移动时,UI后面的图像几乎保持静止。要在macOS上执行此操作,我想获取窗口的坐标。 如何获取窗口的坐标?
我之所以这样问,是因为我在任何地方都找不到该怎么做的信息:
Google搜索帮助我找到了以下结果:
Apple开发人员文档:
GeometryReader
-我希望它会包含一个API,以在系统坐标空间中为我提供框架,但是似乎所有方法只包含窗口内坐标其他SO问题:
(0, 0)
的起源GeometryReader
给出的坐标转换为屏幕坐标,但不幸的是,坐标再次被限制在窗口内网络上的其他地方:
正如我列出的那样,我发现所有这些与我的问题无关,或者仅引用窗口内的坐标,而不引用屏幕内的窗口坐标。有些人提到了使用AppKit的方法,但我想尽可能避免这种情况。
最近的一次尝试使用这样的GeometryReader
:
GeometryReader { geometry in
Text(verbatim: "\(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
不是真实的;它没有指向EnvironmentValues
上的任何键路径。我找不到在哪里可以得到这样的价值。
答案 0 :(得分:0)
如果您想要窗框:
SceneDelegate会跟踪所有窗口,因此您可以使用它来参考它们的框架制作一个EnvironmentObject
并将其传递给View。在委托方法中更新环境对象的值:func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, ...
如果它是一个单窗口应用程序,那就更简单了。您可以在视图中使用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 App,使用“框架更改通知”并将其作为环境对象传递到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
}
}
struct ContentView: View {
@EnvironmentObject var windowInfo: WindowInfo
var body: some View {
Group {
Text("Hello, World! \(windowInfo.frame.debugDescription)")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}