iOS 17中UIView转PDF失效及卡顿问题求助
iOS 17 下 PDFView 渲染卡顿的解决方案
方案一:优化 drawHierarchy 调用逻辑
drawHierarchy(in:afterScreenUpdates:) 传入 afterScreenUpdates: true 会强制触发UI刷新,这是iOS17后卡顿的核心原因之一。改成false并确保视图已完成布局后再调用,同时将PDF写入操作移到后台线程(注意:drawHierarchy必须在主线程执行,仅将PDFRenderer的写入逻辑放后台)。
示例代码:
DispatchQueue.global().async { let render = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: size.width, height: size.height)) do { try render.writePDF(to: path, withActions: { context in context.beginPage() // 切回主线程执行视图渲染 DispatchQueue.main.sync { pdfView.drawHierarchy(in: CGRect(x: 0, y: 0, width: size.width, height: size.height), afterScreenUpdates: false) } }) DispatchQueue.main.async { completion(true, path) } } catch { DispatchQueue.main.async { completion(false, nil) } } }
方案二:直接渲染 PDFDocument(推荐)
避免渲染UIView,直接利用PDFKit的原生API从PDFDocument生成PDF,性能远高于视图渲染,且支持后台线程执行。
示例代码:
DispatchQueue.global().async { guard let document = pdfView.document else { DispatchQueue.main.async { completion(false, nil) } return } let render = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: size.width, height: size.height)) do { try render.writePDF(to: path, withActions: { context in let pageCount = document.pageCount for pageIndex in 0..<pageCount { guard let page = document.page(at: pageIndex) else { continue } context.beginPage() let pageBounds = page.bounds(for: .mediaBox) let scale = min(size.width / pageBounds.width, size.height / pageBounds.height) context.cgContext.scaleBy(x: scale, y: scale) page.draw(with: .mediaBox, to: context.cgContext) } }) DispatchQueue.main.async { completion(true, path) } } catch { DispatchQueue.main.async { completion(false, nil) } } }
方案三:修复 SwiftUI ImageRenderer 渲染空内容问题
如果使用SwiftUI的ImageRenderer,需确保ScrollView的内容已完全加载并布局完成,可通过状态标记或延迟渲染给视图足够的布局时间。
示例代码:
struct ContentView: View { @State private var isReadyToRender = false let scrollContent: some View let path: URL let completion: (Bool, URL?) -> Void var body: some View { ScrollView { scrollContent .onAppear { // 延迟确保内容布局完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { isReadyToRender = true } } } .onChange(of: isReadyToRender) { _, newValue in guard newValue else { return } let renderer = ImageRenderer(content: scrollContent) renderer.scale = UIScreen.main.scale if let image = renderer.uiImage { saveImageAsPDF(image: image) } } } func saveImageAsPDF(image: UIImage) { DispatchQueue.global().async { let render = UIGraphicsPDFRenderer(bounds: CGRect(origin: .zero, size: image.size)) do { try render.writePDF(to: path) { context in image.draw(in: CGRect(origin: .zero, size: image.size)) } DispatchQueue.main.async { completion(true, path) } } catch { DispatchQueue.main.async { completion(false, nil) } } } } }
内容的提问来源于stack exchange,提问作者Rounak
相关产品推荐
相关产品推荐

