Skip to content

Instantly share code, notes, and snippets.

@justinyanme
Last active November 24, 2023 05:24
Show Gist options
  • Save justinyanme/76d9cecd15e991e6afca2c747c772620 to your computer and use it in GitHub Desktop.
Save justinyanme/76d9cecd15e991e6afca2c747c772620 to your computer and use it in GitHub Desktop.
SwiftUI Notes 03
import SwiftUI
import AppKit
extension View {
public func inject<SomeView>(_ view: SomeView) -> some View where SomeView: View {
overlay(view.frame(width: 0, height: 0))
}
func getWindow(window: @escaping (_ window: NSWindow?) -> Void) -> some View {
inject(IntrospectWindowViewRepresentable(getWindow: window))
}
}
struct IntrospectWindowViewRepresentable: NSViewRepresentable {
let getWindow: (_ window: NSWindow?) -> Void
init(getWindow: @escaping (_: NSWindow?) -> Void) {
self.getWindow = getWindow
}
func makeNSView(context: Context) -> some NSView {
let view = IntrospectWindowView(getWindow: self.getWindow)
return view
}
func updateNSView(_ nsView: NSViewType, context: Context) {
// self.getWindow(window: )
}
}
class IntrospectWindowView: NSView {
let getWindow: (_ window: NSWindow?) -> Void
init(getWindow: @escaping (_: NSWindow?) -> Void) {
self.getWindow = getWindow
super.init(frame: .zero)
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("Create this view programmatically.")
}
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
DispatchQueue.main.async {
self.getWindow(self.window)
}
}
}
// Sample Code for Blog Post: How to access window from SwiftUI view?(Chinese) -> https://justinyan.me/post/5656
final class MainWindowController: NSWindowController {
private var mainViewModel: MainViewModel? = nil
convenience init() {
let window = NSWindow.centeredWindow(size: .zero)
let mainViewModel = MainViewModel()
let mainView: MainView = MainView(viewModel: mainViewModel)
window.contentViewController = NSHostingController(rootView: mainView)
window.centerNatural()
window.toolbarStyle = .unifiedCompact
window.styleMask = [.closable, .miniaturizable, .unifiedTitleAndToolbar, .titled, .fullSizeContentView]
window.titlebarAppearsTransparent = true
self.init(window: window)
self.mainViewModel = mainViewModel
NSApp.activate(ignoringOtherApps: false)
window.makeKeyAndOrderFront(nil)
}
}
// Sample Code for Blog Post: How to access window from SwiftUI view?(Chinese) -> https://justinyan.me/post/5656
// WindowReader source code From project -> https://github.com/aheze/Popovers
import Foundation
import AppKit
import SwiftUI
public struct WindowReader<Content: View>: View {
/// Your SwiftUI view.
public let view: (NSWindow?) -> Content
/// The read window.
@StateObject var windowViewModel = WindowViewModel()
/// Reads the `NSWindow` that hosts some SwiftUI content.
public init(@ViewBuilder view: @escaping (NSWindow?) -> Content) {
self.view = view
}
public var body: some View {
view(windowViewModel.window)
// .id(windowViewModel.window)
.background(
WindowViewRepresentable(windowViewModel: windowViewModel)
)
}
/// A wrapper view to read the parent window.
private struct WindowViewRepresentable: NSViewRepresentable {
@ObservedObject var windowViewModel: WindowViewModel
func makeNSView(context _: Context) -> WindowView {
return WindowView(windowViewModel: self.windowViewModel)
}
func updateNSView(_: WindowView, context _: Context) {}
}
private class WindowView: NSView {
var windowViewModel: WindowViewModel
init(windowViewModel: WindowViewModel) {
self.windowViewModel = windowViewModel
super.init(frame: .zero)
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("Should not init with coder")
}
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
DispatchQueue.main.async {
/// Set the window.
self.windowViewModel.window = self.window
}
}
}
}
class WindowViewModel: ObservableObject {
@Published var window: NSWindow?
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment