如何在UIGraphicsImageRenderer中绘制并合并多个图层?
UIGraphicsImageRenderer中合并多图层的崩溃解决方法
问题描述
在将原有CGContext绘图代码迁移到UIGraphicsImageRenderer时,使用CGLayer绘制内容后调用cgContext.draw(layer, at: .zero)会崩溃,且仅当图层包含绘制内容时触发(空图层无报错)。移除该行代码后,主上下文绘制正常,但缺失图层内容。原代码示例:
let renderer = UIGraphicsImageRenderer(size: size) let image = renderer.image { imageContext in let cgContext = imageContext.cgContext // 原有代码逻辑 let layer = CGLayer(cgContext, size: size, auxiliaryInfo: nil)! let layerCGContext = layer.context! // 示例绘制操作(实际逻辑更复杂) cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)]) layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)]) // 此处崩溃:合并图层到主上下文 cgContext.draw(layer, at: .zero) }
崩溃原因
UIGraphicsImageRenderer的上下文是Apple针对iOS/macOS图形栈优化后的封装,直接使用CGLayer的上下文绘制后再将图层绘制回主上下文,会触发上下文状态的冲突,导致崩溃。
解决方案
方法一:嵌套使用UIGraphicsImageRenderer渲染图层内容
推荐使用这种方式,更贴合UIGraphicsImageRenderer的设计模式,避免上下文状态问题:
let renderer = UIGraphicsImageRenderer(size: size) let image = renderer.image { imageContext in let cgContext = imageContext.cgContext // 主上下文绘制基础内容 cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)]) // 单独用渲染器生成图层内容的图像 let layerRenderer = UIGraphicsImageRenderer(size: size) let layerImage = layerRenderer.image { layerContext in let layerCGContext = layerContext.cgContext // 执行图层的绘制操作 layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)]) } // 将图层图像绘制到主上下文 layerImage.draw(at: .zero) }
方法二:通过CGImage中转CGLayer内容(兼容原有CGLayer逻辑)
如果需要保留原有CGLayer的使用逻辑,可以将图层内容转为CGImage后再绘制到主上下文:
let renderer = UIGraphicsImageRenderer(size: size) let image = renderer.image { imageContext in let cgContext = imageContext.cgContext // 主上下文绘制基础内容 cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)]) // 创建并绘制CGLayer let layer = CGLayer(cgContext, size: size, auxiliaryInfo: nil)! let layerCGContext = layer.context! layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)]) // 将CGLayer转为CGImage再绘制到主上下文 UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) defer { UIGraphicsEndImageContext() } if let tempContext = UIGraphicsGetCurrentContext() { tempContext.draw(layer, at: .zero) if let layerCGImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage { cgContext.draw(layerCGImage, in: CGRect(origin: .zero, size: size)) } } }
说明
方法一是更优的选择,它利用UIGraphicsImageRenderer的封装特性,避免了手动管理上下文的状态冲突;方法二则适合需要快速兼容原有CGLayer代码的场景。
内容的提问来源于stack exchange,提问作者Ze Jibe
相关产品推荐
相关产品推荐

