appkit-bridge
4
总安装量
3
周安装量
#49433
全站排名
安装命令
npx skills add https://github.com/makgunay/claude-swift-skills --skill appkit-bridge
Agent 安装分布
opencode
3
claude-code
3
codex
3
cursor
3
gemini-cli
2
github-copilot
2
Skill 文档
AppKit Bridge â SwiftUI â AppKit Integration
Critical Constraints
- â DO NOT use
NSViewControlleras app architecture â â Use SwiftUIApp+Scene, bridge only where needed - â DO NOT use
NSViewsubclass when SwiftUI modifier exists â â Check SwiftUI first, bridge as last resort - â DO NOT forget
makeCoordinator()for delegate callbacks â â Use Coordinator pattern for NSViewRepresentable - â DO NOT call
makeNSViewto update â â UseupdateNSView(_:context:)for state changes
NSViewRepresentable (AppKit â SwiftUI)
import SwiftUI
import AppKit
struct WrappedNSView: NSViewRepresentable {
var text: String
func makeNSView(context: Context) -> NSTextField {
let field = NSTextField()
field.delegate = context.coordinator
return field
}
func updateNSView(_ nsView: NSTextField, context: Context) {
nsView.stringValue = text
}
func makeCoordinator() -> Coordinator { Coordinator(self) }
class Coordinator: NSObject, NSTextFieldDelegate {
var parent: WrappedNSView
init(_ parent: WrappedNSView) { self.parent = parent }
func controlTextDidChange(_ obj: Notification) {
// Handle text changes
}
}
}
NSHostingView (SwiftUI â AppKit)
let swiftUIView = MySwiftUIView()
let hostingView = NSHostingView(rootView: swiftUIView)
hostingView.translatesAutoresizingMaskIntoConstraints = false
// Add to AppKit view hierarchy
parentView.addSubview(hostingView)
NSLayoutConstraint.activate([
hostingView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
hostingView.trailingAnchor.constraint(equalTo: parentView.trailingAnchor),
hostingView.topAnchor.constraint(equalTo: parentView.topAnchor),
hostingView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor),
])
NSPanel â Floating Window
class FloatingPanel: NSPanel {
init(contentView: NSView) {
super.init(
contentRect: NSRect(x: 0, y: 0, width: 600, height: 400),
styleMask: [.nonactivatingPanel, .titled, .closable, .fullSizeContentView],
backing: .buffered, defer: true
)
titlebarAppearsTransparent = true
titleVisibility = .hidden
isOpaque = false
backgroundColor = .clear
level = .floating
collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .transient]
isMovableByWindowBackground = true
hidesOnDeactivate = false
self.contentView = contentView
center()
}
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { false }
}
// Host SwiftUI content
let panel = FloatingPanel(contentView: NSHostingView(rootView: MyView()))
Show/Hide with Animation
extension FloatingPanel {
func showCentered() {
center()
alphaValue = 0
makeKeyAndOrderFront(nil)
NSAnimationContext.runAnimationGroup { ctx in
ctx.duration = 0.15
ctx.timingFunction = CAMediaTimingFunction(name: .easeOut)
animator().alphaValue = 1
}
}
func hideAnimated() {
NSAnimationContext.runAnimationGroup({ ctx in
ctx.duration = 0.1
ctx.timingFunction = CAMediaTimingFunction(name: .easeIn)
animator().alphaValue = 0
}, completionHandler: { self.orderOut(nil) })
}
}
NSPopover
let popover = NSPopover()
popover.contentViewController = NSHostingController(rootView: PopoverContent())
popover.behavior = .transient
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
popover.contentViewController?.view.window?.makeKey()
Window Positioning
extension NSPanel {
func centerOnActiveScreen() {
guard let screen = NSScreen.main ?? NSScreen.screens.first else { return }
let frame = screen.visibleFrame
setFrameOrigin(NSPoint(x: frame.midX - self.frame.width / 2,
y: frame.midY - self.frame.height / 2))
}
}
Decision Tree
Need a floating overlay? â NSPanel + NSHostingView
Need a menu bar popover? â NSPopover + NSHostingController
Need custom window chrome? â NSWindow subclass + titlebarAppearsTransparent
Need AppKit control in SwiftUI? â NSViewRepresentable
Need SwiftUI view in AppKit? â NSHostingView or NSHostingController
Need glass effect in AppKit? â NSGlassEffectView (see liquid-glass skill)