你如何将 macOS SwiftUI 视图转换为图像?

3
我知道你可以按照这些步骤将iOS SwiftUI View转换成图像,但在SwiftUI for macOS中,这会使用SwiftUI扩展中不能使用的UIKit元素。
有人知道如何快照/截屏macOS SwiftUI View吗?

1
那个链接是关于SwiftUI的。 - undefined
@loremipsum 是的,但它包含了macOS SwiftUI无法使用的UIKit组件。 - undefined
2个回答

7
在 macOS 中可以使用相同的方法。 NSHostingControllerUIHostingController 的类比版本。此外,要使其绘制视图,应将该视图添加到某个窗口中:
extension View {
    func snapshot() -> NSImage? {
        let controller = NSHostingController(rootView: self)
        let targetSize = controller.view.intrinsicContentSize
        let contentRect = NSRect(origin: .zero, size: targetSize)
        
        let window = NSWindow(
            contentRect: contentRect,
            styleMask: [.borderless],
            backing: .buffered,
            defer: false
        )
        window.contentView = controller.view
        
        guard
            let bitmapRep = controller.view.bitmapImageRepForCachingDisplay(in: contentRect)
        else { return nil }
        
        controller.view.cacheDisplay(in: contentRect, to: bitmapRep)
        let image = NSImage(size: bitmapRep.size)
        image.addRepresentation(bitmapRep)
        return image
    }
}

非常感谢!我尝试了很多不同的代码片段,希望能让它起作用,但是这个最终有所作为。然而,我需要将从controller.view.cacheDisplay开始的所有内容放入一个DispatchQueue.main.async块中,并通过完成处理程序返回结果。目前,我还在硬编码targetSize,因为我的视图没有返回正确的intrinsicContentSize,但这是一个无关的问题。 - undefined
好的,原来如果你使用.frame(...)显式设置视图的大小,那么不仅intrinsicContentSize有效,而且你还可以调用window.contentView?.layout()(没有定义大小也不会崩溃)使其在不使用DispatchQueue.main.async的情况下正常工作。 - undefined

0

macOS 13.0+的SwiftUI本地快照技术

使用SwiftUI的ImageRenderer对象将macOS视图光栅化为NSImage。

以下是代码:

import SwiftUI

@MainActor final class BitmapImage : ObservableObject {
    
    @Published var images: [String: NSImage] = [:]

    init() {
        let view = SampleView()
        let renderer = ImageRenderer(content: view)
        
        #if os(macOS)
            renderer.scale = NSApplication.shared
                                          .mainWindow?
                                          .backingScaleFactor ?? 2.0
        
            if let nsImage = renderer.nsImage {
                images["1"] = nsImage
            }
        #endif
    }
}

struct SampleView : View {
    var body: some View {
        ZStack {
            Image("picture")
            VStack {
                Divider()
                Text("Lorem ipsum dolor sit amet")
                    .foregroundColor(.white)
                    .font(.custom("", size: 72))
                Spacer()
            }
        }
    }
}

enter image description here

@available(macOS 13.0, *) struct ContentView : View {
    
    @StateObject private var bitmapImage = BitmapImage()
    
    var body: some View {
        ZStack {
            if let nsImage = bitmapImage.images["1"] {
                Image(nsImage: nsImage)
                    .resizable()
                    .frame(width: 500)      // "Squeezed" Image test
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接