我想制作一个视差背景视图,当窗口在屏幕上移动时,UI 后面的图像几乎保持静止。要在 macOS 上执行此操作,我想获取窗口的坐标。我如何获得窗口的坐标?
我问这个是因为我找不到任何说明如何做到这一点的地方:
谷歌搜索帮助我找到了以下结果:
苹果开发者文档:
GeometryReader - 我曾希望这将包含一个 API 来为我提供系统坐标空间中的框架,但似乎所有方法都只包含参考窗口内坐标其他问题:
(0, 0)来源GeometryReader为屏幕坐标,但不幸的是坐标再次被限制在窗口内网络上的其他地方:
正如我列出的那样,我发现所有这些要么与我的问题无关,要么只引用了窗口内的坐标,而不是屏幕内窗口的坐标。有些人提到了使用 AppKit 的方法,但我想尽可能避免这种情况。
我得到的最接近的是尝试使用GeometryReader这样的:
GeometryReader { geometry in
Text(verbatim: "\(geometry.frame(in: .global))")
}
Run Code Online (Sandbox Code Playgroud)
但原点始终是(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)
}
}
Run Code Online (Sandbox Code Playgroud)
但\.windowFrame不是真实的;它没有指向EnvironmentValues. 我找不到在哪里可以获得这样的价值。
如果你想要窗框:
SceneDelegate 跟踪所有窗口,因此您可以使用它来创建EnvironmentObject对其框架的引用并将其传递给您的视图。更新委托方法中的环境对象值: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)
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
但话虽如此,通常您不需要绝对框架。对齐参考线可让您将事物相对放置。
// 对于 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
}
}
Run Code Online (Sandbox Code Playgroud)
struct ContentView: View {
@EnvironmentObject var windowInfo: WindowInfo
var body: some View {
Group {
Text("Hello, World! \(windowInfo.frame.debugDescription)")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1441 次 |
| 最近记录: |