Skip to content

Instantly share code, notes, and snippets.

@hishnash
Created December 21, 2020 05:59
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hishnash/c4ce28f749a87dd9502a30af34b1b266 to your computer and use it in GitHub Desktop.
Save hishnash/c4ce28f749a87dd9502a30af34b1b266 to your computer and use it in GitHub Desktop.
Access to the underlying UIWindow & NSWindow in swiftUI gives access to window methods and attributes.
//
// ExampleWindowReaderApp.swift
// Shared
//
// Created by Matthaus Woolard on 21/12/2020.
//
import SwiftUI
@main
struct ExampleWindowReaderApp: App {
var body: some Scene {
WindowGroup {
ContentView().modifier(WindowObservationModifier())
}
}
}
#if canImport(UIKit)
typealias Window = UIWindow
#elseif canImport(AppKit)
typealias Window = NSWindow
#else
#error("Unsupported platform")
#endif
class WindowObserver: ObservableObject {
@Published
public private(set) var isKeyWindow: Bool = false
private var becomeKeyobserver: NSObjectProtocol?
private var resignKeyobserver: NSObjectProtocol?
weak var window: Window? {
didSet {
self.isKeyWindow = window?.isKeyWindow ?? false
guard let window = window else {
self.becomeKeyobserver = nil
self.resignKeyobserver = nil
return
}
self.becomeKeyobserver = NotificationCenter.default.addObserver(
forName: Window.didBecomeKeyNotification,
object: window,
queue: .main
) { (n) in
self.isKeyWindow = true
}
self.resignKeyobserver = NotificationCenter.default.addObserver(
forName: Window.didResignKeyNotification,
object: window,
queue: .main
) { (n) in
self.isKeyWindow = false
}
}
}
}
extension EnvironmentValues {
struct IsKeyWindowKey: EnvironmentKey {
static var defaultValue: Bool = false
typealias Value = Bool
}
fileprivate(set) var isKeyWindow: Bool {
get {
self[IsKeyWindowKey.self]
}
set {
self[IsKeyWindowKey.self] = newValue
}
}
}
struct WindowObservationModifier: ViewModifier {
@StateObject
var windowObserver: WindowObserver = WindowObserver()
func body(content: Content) -> some View {
content.background(
HostingWindowFinder { [weak windowObserver] window in
windowObserver?.window = window
}
).environment(\.isKeyWindow, windowObserver.isKeyWindow)
}
}
#if canImport(UIKit)
struct HostingWindowFinder: UIViewRepresentable {
var callback: (Window?) -> ()
func makeUIView(context: Context) -> UIView {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
#elseif canImport(AppKit)
struct HostingWindowFinder: NSViewRepresentable {
var callback: (Window?) -> ()
func makeNSView(context: Self.Context) -> NSView {
let view = NSView()
view.translatesAutoresizingMaskIntoConstraints = false
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
#else
#error("Unsupported platform")
#endif
@xiaoxidong
Copy link

I add this code to my project and has a error? any idea why? The error below.
Undefined symbols for architecture x86_64:
"(extension in Poke):SwiftUI.EnvironmentValues.isKeyWindow.setter : Swift.Bool", referenced from:
key path setter for (extension in Poke):SwiftUI.EnvironmentValues.isKeyWindow : Swift.Bool : SwiftUI.EnvironmentValues in PokeApp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

@hishnash
Copy link
Author

@xiaoxidong That is a strange error to get. What version of Xcode are you running? And have you cleaned your build folder?

@xwischi
Copy link

xwischi commented Mar 14, 2021

Same to me on Xcode 12.4

@hishnash
Copy link
Author

@xwischi does this package build and work? https://github.com/LostMoa/KeyWindow

@monesga
Copy link

monesga commented Jun 4, 2021

It's probably the fileprivate(set) var isKeyWindow: Bool ... part

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment