【问题标题】:Create a PDF file from a specific View从特定视图创建 PDF 文件
【发布时间】:2021-02-03 10:42:17
【问题描述】:

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

Convert SwiftUI View to PDF on iOS

// 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()
    }

【问题讨论】:

    标签: ios pdf swiftui


    【解决方案1】:

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

    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 的视图中使用此功能。这自然会导致无限循环。

    我希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      来自链接问题的答案:

      您在所有其他视图后面的窗口上呈现 HostingController,并在 PDF 上绘制其层。

      这将是第一个视图,我猜是索引 0。从您提供的功能来看,这一行看起来很相关:

      rootVC?.view.insertSubview(pdfVC.view, at: 0)
      

      0 替换为您想要的视图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-03
        • 2013-03-26
        相关资源
        最近更新 更多