如何在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 here

let 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

回到顶部