AppKit 中的 SwiftUI 视图到 NSImage

Alb*_*tUI 9 appkit swift swiftui

SwiftUI 2.0 | 斯威夫特 5.4 | Xcode 12.4 | macOS 大苏尔 11.4

在 iOS 中,有一种方法可以将 SwiftUI 视图渲染为 UIImage,但该方法在 AppKit 中不起作用,仅在 UIKit 中起作用:

extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view

        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear

        let renderer = UIGraphicsImageRenderer(size: targetSize)

        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么解决方法可以让它在 AppKit 上运行吗?该方法UIGraphicsImageRenderer(size:)不适用于 AppKit,并且没有等效方法。

Qui*_*inn 1

如果我正确理解你的问题,你应该能够使用 NSBitmapImageRef 来解决这个问题!

下面是一个NSImage从 SwiftUI 视图生成的简单示例(注意:您的宿主视图必须可见!):


let view = MyView() // some SwiftUI view
let host = NSHostingView(rootView: view)

// Note: the host must be visible on screen, which I am guessing you already have it that way. If not, do that here.

let bitmapRep = host.bitmapImageRepForCachingDisplay(in: host.bounds)
host.cacheDisplay(in: host.bounds, to: bitmapRep!)

let image = NSImage(size: host.frame.size)
image.addRepresentation(bitmapRep!)
Run Code Online (Sandbox Code Playgroud)

这是应该安全地制作快照的扩展NSHostingView

extension NSHostingView {
    func snapshot() -> NSImage? {
        // Make sure the view is visible:
        guard self.window != nil else { return nil }

        // Get bitmap data:
        let bitmapRep = self.bitmapImageRepForCachingDisplay(in:
        self.bounds)
        self.cacheDisplay(in: self.bounds, to: bitmapRep!)

        // Create NSImage from NSBitmapImageRep:
        let image = NSImage(size: self.frame.size)
        image.addRepresentation(bitmapRep!)
        
        return image
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助。如果您有任何疑问,请告诉我!