首页 > 解决方案 > 从特定视图创建 PDF 文件

问题描述

我想从视图 X 创建一个 PDF 文件。从 Alex 的问题中报告和提取的代码有效,但只创建了主视图的 PDF(视图 A)。我如何告诉他创建 View X 的 PDF?

在 iOS 上将 SwiftUI 视图转换为 PDF

// From Main View A
func savePdf() {
        let view = ViewX() // <--- This is the View I would like to transform, not linked to View A
        let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let outputFileURL = documentDirectory.appendingPathComponent("ViewX.pdf")

        let dpiScale: CGFloat = 4

        // for A5 page size inches * 72
        let pageSize = CGSize(width: 5.8 * 72, height: 8.3 * 72)
        
        let pdfVC = UIHostingController(rootView: view) 
        pdfVC.view.frame = CGRect(origin: .zero, size: pageSize * dpiScale)

        let rootVC = UIApplication.shared.windows.first?.rootViewController
        rootVC?.addChild(pdfVC)
        rootVC?.view.insertSubview(pdfVC.view, at: 0)

        let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(origin: .zero, size: pageSize))

        DispatchQueue.main.async {
            do {
                try pdfRenderer.writePDF(to: outputFileURL, withActions: { (context) in
                    context.beginPage()
                    rootVC?.view.layer.render(in: context.cgContext)
                    self.pdfURL = outputFileURL
                })
            } catch {
                print("error.localizedDescription")
            }
        }
        pdfVC.removeFromParent()
        pdfVC.view.removeFromSuperview()
    }

标签: iospdfswiftui

解决方案


我有同样的问题。这对我有用:

import SwiftUI

func exportToPDF() {
    let outputFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("SwiftUI.pdf")
    let pageSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    
    //View to render on PDF
    let myUIHostingController = UIHostingController(rootView: ContentView())
    myUIHostingController.view.frame = CGRect(origin: .zero, size: pageSize)
    
    
    //Render the view behind all other views
    guard let rootVC = UIApplication.shared.windows.first?.rootViewController else {
        print("ERROR: Could not find root ViewController.")
        return
    }
    rootVC.addChild(myUIHostingController)
    //at: 0 -> draws behind all other views
    //at: UIApplication.shared.windows.count -> draw in front
    rootVC.view.insertSubview(myUIHostingController.view, at: 0)
    
    
    //Render the PDF
    let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(origin: .zero, size: pageSize))
    DispatchQueue.main.async {
        do {
            try pdfRenderer.writePDF(to: outputFileURL, withActions: { (context) in
                context.beginPage()
                myUIHostingController.view.layer.render(in: context.cgContext)
            })
            print("wrote file to: \(outputFileURL.path)")
        } catch {
            print("Could not create PDF file: \(error.localizedDescription)")
        }
        
        //Remove rendered view
        myUIHostingController.removeFromParent()
        myUIHostingController.view.removeFromSuperview()
    }
}

注意:当您尝试导出同一个视图时,不要尝试在带有 .onAppear 的视图中使用此功能。这自然会导致无限循环。

我希望这有帮助!


推荐阅读