如何程序化截取含UIView、MTKView与SwiftUI View的混合视图截图?
解决混合视图层级(SwiftUI/UIView/MTKView)的截图问题
方法1:结合drawHierarchy与MTKView帧捕获
常规的drawHierarchy(in:afterScreenUpdates:)能捕获大部分UIKit/SwiftUI视图,但MTKView的Metal内容需要单独提取后合并到整体截图:
- 先提取MTKView当前渲染帧转成
UIImage:func mtkViewToImage(_ mtkView: MTKView) -> UIImage? { guard let drawable = mtkView.currentDrawable, let texture = drawable.texture else { return nil } let ciImage = CIImage(mtlTexture: texture, options: [.colorSpace: CGColorSpaceCreateDeviceRGB()]) guard let cgImage = CIContext().createCGImage(ciImage, from: ciImage.extent) else { return nil } return UIImage(cgImage: cgImage) } - 调用
drawHierarchy获取基础视图截图:func captureHostView(_ hostView: UIView) -> UIImage? { UIGraphicsBeginImageContextWithOptions(hostView.bounds.size, hostView.isOpaque, UIScreen.main.scale) hostView.drawHierarchy(in: hostView.bounds, afterScreenUpdates: true) let baseImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return baseImage } - 将MTKView的截图绘制到基础截图的对应位置,得到完整的混合视图截图。
方法2:捕获当前窗口的完整屏幕内容
如果视图已显示在屏幕上,直接捕获窗口内容可以自动包含MTKView的渲染像素:
func captureWindow() -> UIImage? { guard let window = UIApplication.shared.connectedScenes .compactMap({ $0 as? UIWindowScene }) .first?.windows.first else { return nil } let renderer = UIGraphicsImageRenderer(size: window.bounds.size) return renderer.image { context in window.drawHierarchy(in: window.bounds, afterScreenUpdates: true) } }
方法3:修改MTKView配置适配常规截图
调整MTKView的渲染设置,让其内容同步到CALayer,这样常规截图方法就能直接捕获:
// 初始化MTKView时配置 mtkView.enableSetNeedsDisplay = true mtkView.preferredFramesPerSecond = 60 // 在MTKViewDelegate的draw(in:)方法末尾添加 func draw(in view: MTKView) { // 你的Metal渲染逻辑 view.setNeedsDisplay() }
配置完成后,使用ImageRenderer或drawHierarchy即可直接捕获包含MTKView的完整视图。
内容的提问来源于stack exchange,提问作者Son Nguyen
相关产品推荐
相关产品推荐

