如何在SwiftUI视图中访问自己的窗口?
目标是可以轻松访问任何级别的SwiftUI视图层次结构的托管窗口。目的可能有所不同-
关闭窗口,退出第一响应者,替换根视图或contentViewController。与UIKit / AppKit集成有时也需要通过窗口的路径,因此…
我在这里遇到和尝试过的
像这样的东西
let keyWindow = shared.connectedScenes .filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
或通过在每个SwiftUI视图中添加UIViewRepresentable /
NSViewRepresentable来使用view.window
看起来丑陋,沉重且不可用的窗口。
因此,我该怎么做?
回答:
这是我的实验结果,很适合我,因此可能对您有所帮助。已通过Xcode 11.2 / iOS 13.2 / macOS 15.0测试
该想法是使用本机SwiftUI环境概念,因为一旦注入的环境值将自动用于整个视图层次结构。所以
1)定义环境密钥。注意,需要记住避免在保留窗口上循环引用
struct HostingWindowKey: EnvironmentKey {#if canImport(UIKit)
typealias WrappedValue = UIWindow
#elseif canImport(AppKit)
typealias WrappedValue = NSWindow
#else
#error("Unsupported platform")
#endif
typealias Value = () -> WrappedValue? // needed for weak link
static let defaultValue: Self.Value = { nil }
}
extension EnvironmentValues {
var hostingWindow: HostingWindowKey.Value {
get {
return self[HostingWindowKey.self]
}
set {
self[HostingWindowKey.self] = newValue
}
}
}
2)将托管窗口注入到根ContentView中,而不是创建窗口(在AppDelegate或SceneDelegate中仅一次)
// window created herelet contentView = ContentView()
.environment(\.hostingWindow, { [weak window] in
return window })
#if canImport(UIKit)
window.rootViewController = UIHostingController(rootView: contentView)
#elseif canImport(AppKit)
window.contentView = NSHostingView(rootView: contentView)
#else
#error("Unsupported platform")
#endif
3)仅在需要的地方使用,只需声明环境变量
struct ContentView: View { @Environment(\.hostingWindow) var hostingWindow
var body: some View {
VStack {
Button("Action") {
// self.hostingWindow()?.close() // macOS
// self.hostingWindow()?.makeFirstResponder(nil) // macOS
// self.hostingWindow()?.resignFirstResponder() // iOS
// self.hostingWindow()?.rootViewController?.present(UIKitController(), animating: true)
}
}
}
}
以上是 如何在SwiftUI视图中访问自己的窗口? 的全部内容, 来源链接: utcz.com/qa/397892.html