首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在SwiftUI中获得窗口坐标?

如何在SwiftUI中获得窗口坐标?
EN

Stack Overflow用户
提问于 2020-06-07 22:23:40
回答 2查看 2.6K关注 0票数 8

我想要做一个视差背景视图,在那里,用户界面后面的图像几乎保持不变,因为窗口在屏幕上移动。要在macOS上这样做,我想要得到窗口的坐标。如何获得窗口的坐标?

我问这个是因为我找不到任何地方说该怎么做:

  • 谷歌搜索帮助我找到了以下结果:
代码语言:javascript
复制
- [SwiftUI window coordinates](https://www.google.com/search?q=SwiftUI+window+coordinates), [SwiftUI window location](https://www.google.com/search?q=SwiftUI+window+location), [SwiftUI window get frame](https://www.google.com/search?q=SwiftUI+window+get+frame), [SwiftUI get window](https://www.google.com/search?q=SwiftUI+get+window), [SwiftUI macOS window coordinates](https://www.google.com/search?q=SwiftUI+macOS+window+coordinates), [SwiftUI macOS window location](https://www.google.com/search?q=SwiftUI+macOS+window+location), [SwiftUI macOS window get frame](https://www.google.com/search?q=SwiftUI+macOS+window+get+frame), [SwiftUI macOS get window](https://www.google.com/search?q=SwiftUI+macOS+get+window)

  • Apple Developer文档:
代码语言:javascript
复制
- [`GeometryReader`](https://developer.apple.com/documentation/swiftui/geometryreader) - I had hoped that this would contain an API to give me the frame in system coordinate space, but it seems all the approaches it contains only reference within-the-window coordinates
- [Creating a macOS App — SwiftUI Tutorials](https://developer.apple.com/tutorials/swiftui/creating-a-macos-app) - I was hoping Apple would have mentioned windowing in this, but it's not mentioned at all, aside from saying that you can preview the main window's contents in an Xcode preview pane
- Fruitless searches: [SwiftUI window coordinates](https://developer.apple.com/search/?q=SwiftUI%20window%20coordinates), [SwiftUI window location](https://developer.apple.com/search/?q=SwiftUI%20window%20location), [SwiftUI window get frame](https://developer.apple.com/search/?q=SwiftUI%20window%20get%20frame)

  • 其他问题如下:
代码语言:javascript
复制
- [How to access own window within SwiftUI view?](https://stackoverflow.com/q/60359808/3939277) - I was optimistic that this would have an answer which would give me a SwiftUI API to access the window, but instead it uses a shim to access the AppKit window representation.
- [Define macOS window size using SwiftUI](https://stackoverflow.com/q/56857782/3939277) - Similar hopes as the above question, but this time the answer was just to read the frame of the content view, which again, always has a `(0, 0)` origin
- [SwiftUI coordinate space](https://stackoverflow.com/q/56443486/3939277) - I was hoping this answer would let me know how to transform the coordinates given by `GeometryReader` into screen coordinates, but unfortunately the coordinates are again constrained to within the window

  • 在网上的其他地方:
代码语言:javascript
复制
- [SwiftUI for Mac - Part 2](https://troz.net/post/2019/swiftui-for-mac-2/) by [TrozWare](https://troz.net/) - I was hoping that this would give me some tips for using SwiftUI on Mac, such as interacting with windows, since most tutorials focus on iOS/iPadOS. Unfortunately, although it has lots of good information about how SwiftUI works with windows, it has no information on interacting with nor parsing those windows, themselves
- [SwiftUI Layout System](https://kean.github.io/post/swiftui-layout-system) by [Alexander Grebenyuk](https://kean.github.io/) - Was hoping for window layout within the screen, but this is all for full-screen iOS apps
- [SwiftUI by Example](https://www.hackingwithswift.com/quick-start/swiftui) by [Hacking with Swift](https://www.hackingwithswift.com/) - Was hoping for an example for how to get the position of a window, but it seems windows aren't really mentioned at all in the listed examples

正如我所列出的,我发现所有这些都与我的问题无关,或者只是引用窗口内的坐标,而不是引用屏幕中的窗口坐标。有些人提到了使用AppKit的方法,但如果可能的话,我想避免这种情况。

我得到的最接近的是试图使用这样的GeometryReader

代码语言:javascript
复制
GeometryReader { geometry in
    Text(verbatim: "\(geometry.frame(in: .global))")
}

但是原点总是(0, 0),尽管当我调整窗口时,大小确实发生了变化。

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

代码语言:javascript
复制
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上的任何键盘。我找不到我能从哪里得到这样的价值。

EN

回答 2

Stack Overflow用户

发布于 2022-06-19 12:14:37

到目前为止,我们已经广泛部署/安装了macOS 12,而SwiftUI还没有为macOS窗口获得一个合适的模型。根据我到目前为止对macOS 13的了解,窗口也不会有一个SwiftUI模型。

今天(自macOS 11以来),我们不再打开AppDelegate中的窗口,而是使用WindowGroup场景修饰符定义窗口:

代码语言:javascript
复制
@main
struct HandleWindowApp: App {
    var body: some Scene {
        WindowGroup(id: "main") {
            ContentView()
        }
    }
}

但是没有控制或访问底层窗口的标准方法(例如NSWindow)。要做到这一点,堆栈溢出上的多个答案建议使用一个WindowAccessor,它在ContentView的后台安装一个NSView,然后访问它的window属性。我还写了我的版本控制窗口的放置。在您的示例中,只需获得NSWindow实例的句柄,然后观察NSWindow.didMoveNotification即可。每当窗口移动时,它就会被调用。

如果您的应用程序只使用一个窗口(例如,您以某种方式阻止用户创建多个窗口),您甚至可以在全球范围内观察到帧的位置:

代码语言:javascript
复制
NotificationCenter.default
    .addObserver(forName: NSWindow.didMoveNotification, object: nil, queue: nil) { (notification) in
        if let window = notification.object as? NSWindow,
           type(of: window).description() == "SwiftUI.SwiftUIWindow"
        {
            print(window.frame)
        }
    }
票数 2
EN

Stack Overflow用户

发布于 2020-06-08 03:02:44

如果你想要窗框:

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 }

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

代码语言:javascript
复制
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视图

代码语言:javascript
复制
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
    }
  }
代码语言:javascript
复制
struct ContentView: View {
  @EnvironmentObject var windowInfo: WindowInfo

  var body: some View {
    Group  {
      Text("Hello, World! \(windowInfo.frame.debugDescription)")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62252446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档