Skip to content

Instantly share code, notes, and snippets.

@otmb
Last active September 9, 2023 12:53
Show Gist options
  • Save otmb/0fd50f1d8d9d61d8c0c7ed2c19f7a68a to your computer and use it in GitHub Desktop.
Save otmb/0fd50f1d8d9d61d8c0c7ed2c19f7a68a to your computer and use it in GitHub Desktop.
When outputting PDF with SwiftUI, Table cannot be used with ImageRenderer, so use UIGraphicsPDFRenderer
import SwiftUI
struct ContentView: View {
@State var pdfUrl: URL?
var body: some View {
VStack {
if let pdfUrl = pdfUrl {
PreviewView(url: pdfUrl)
}
}
.padding()
.onAppear {
let outputFileURL = try! PdfPage().exportToPDF("sample.pdf", width: 340, height: 600)
pdfUrl = outputFileURL
}
}
}
struct PdfPage : View {
// https://stackoverflow.com/questions/75482532/how-can-i-display-tabular-data-with-swiftui-on-iphone
struct Stat: Identifiable, Equatable {
var id: String { name }
let name: String
let totalMatches: Int
let standingsPoints: Int
}
let stats = [
Stat(name: "Fred", totalMatches: 12, standingsPoints: 87),
Stat(name: "Jim", totalMatches: 4, standingsPoints: 12),
Stat(name: "Dave", totalMatches: 9, standingsPoints: 91)]
var body: some View {
List {
Grid {
GridRow {
Text("Name")
Text("Matches")
Text("Points")
}
.bold()
Divider()
ForEach(stats) { stat in
GridRow {
Text(stat.name)
Text(stat.totalMatches, format: .number)
Text(stat.standingsPoints, format: .number)
}
if stat != stats.last {
Divider()
}
}
}
}
VStack(alignment: .leading) {
Text("Title").font(.largeTitle)
HStack {
ZStack(alignment: .top){
VStack(spacing: 0) {
Rectangle()
.fill(.blue)
.frame(width: 240, height: 50)
.cornerRadius(10, corners: [.topLeft, .topRight])
Rectangle()
.fill(.gray)
.frame(width: 240, height: 50)
}
HStack {
VStack {
Text("Hello")
Divider().padding(5).opacity(0)
Text("Hello")
}
.frame(width: 60, height: 100)
Rectangle()
.fill(.black)
.frame(width: 1, height: 100)
VStack {
Text("Hello")
Divider().padding(5).opacity(0)
Text("Hello")
}
.frame(width: 60, height: 100)
Rectangle()
.fill(.black)
.frame(width: 1, height: 100)
VStack {
Text("Hello")
Divider().padding(5).opacity(0)
Text("Hello")
}
.frame(width: 60, height: 100)
}
.overlay {
Rectangle()
.fill(.black)
.frame(width: 240, height: 1)
}
}
VStack{
Image(systemName: "trash").font(.largeTitle)
Image(systemName: "trash").font(.largeTitle)
Image(systemName: "trash").font(.largeTitle)
Image(systemName: "trash").font(.largeTitle)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct RoundedCorner: Shape {
var radius: CGFloat
var corners: UIRectCorner
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(
roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
)
return Path(path.cgPath)
}
}
extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}
import SwiftUI
import PDFKit
struct PreviewView : UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> some PDFView {
let pdfView = PDFView()
pdfView.document = PDFDocument(url: url)
return pdfView
}
func updateUIView(_ uiView: UIViewType, context: Context) {}
}
func createUrl(fileName: String) throws -> URL {
let fileManager = FileManager.default
let url = fileManager.temporaryDirectory.appendingPathComponent(fileName, conformingTo: .pdf)
if fileManager.fileExists(atPath: url.path) {
try fileManager.removeItem(at: url)
}
return url
}
// https://www.hackingwithswift.com/forums/swift/creating-pdf-from-uiview-in-swift/442
extension View {
func exportToPDF(_ fileName: String, width:CGFloat=595.2, height:CGFloat=841.8) throws -> URL {
let outputFileURL = try createUrl(fileName: fileName)
let pdfVC = UIHostingController(rootView: self)
pdfVC.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
//Render the view behind all other views
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
let rootVC = window?.rootViewController
rootVC?.addChild(pdfVC)
rootVC?.view.insertSubview(pdfVC.view, at: 0)
//Render the PDF
let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: width, height: height))
try pdfRenderer.writePDF(to: outputFileURL, withActions: { (context) in
context.beginPage()
rootVC?.view.layer.render(in: context.cgContext)
})
pdfVC.removeFromParent()
pdfVC.view.removeFromSuperview()
return outputFileURL
}
}
@otmb
Copy link
Author

otmb commented Sep 8, 2023

Result PDF

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment