我正在尝试使用 ImageRenderer 在 PDF 中打印一个简单的表格,但我很挣扎。我对这里的定位和措施感到很困惑。
这是代码:
import SwiftUI
struct Stat: Identifiable, Equatable {
var id: String
let totalMatches: Int
let points: Int
}
struct GridView: View {
let stats: [Stat]
var body: some View {
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
GridRow(alignment: .center) {
Text("ID")
Text("Matches")
Text("Points")
}.frame(maxWidth: .infinity)
.frame(height: 50)
.bold()
.font(.headline)
.background(.pink)
.frame(maxWidth: .infinity)
ForEach(Array(stats.enumerated()), id: \.1.id) { (index, stat) in
GridRow(alignment: .center) {
Text(stat.id)
Text(stat.totalMatches, format: .number)
Text(stat.points, format: .number)
}.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
.background(index % 2 == 0 ? Color.white : Color.gray.opacity(0.2))
}
}
.background(.purple.opacity(0.2))
}
}
struct ExportImagesView: View {
@State private var image = Image(systemName: "heart")
private let pages = ["Page1"]
private let stats = [
Stat(id: UUID().uuidString, totalMatches: 4, points: 12),
Stat(id: UUID().uuidString, totalMatches: 9, points: 31),
Stat(id: UUID().uuidString, totalMatches: 4, points: 14),
Stat(id: UUID().uuidString, totalMatches: 1, points: 0),
]
var body: some View {
VStack(spacing: 20) {
image
Divider()
HStack {
ShareLink("Export", item: render())
Spacer()
Button {
render()
} label: {
Text("Render")
}
}.padding()
}
}
@MainActor
@discardableResult
func render() -> URL {
let url = URL.documentsDirectory.appending(path: "output.pdf")
var box = CGRect(x: 0, y: 0, width: 595.2, height: 841.8)
guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
return url
}
for _ in pages {
pdf.beginPDFPage(nil)
let renderer = ImageRenderer(content: GridView(stats: stats))
renderer.render { size, context in context(pdf)}
pdf.endPDFPage()
}
pdf.closePDF()
if let cgImage = pdf.makeImage() {
let uiImage = UIImage(cgImage: cgImage)
image = Image(uiImage: uiImage)
}
return url
}
}
struct ExportImagesView_Previews: PreviewProvider {
static var previews: some View {
ExportImagesView()
}
}
有两个主要问题。首先,我无法预览 pdf 文件。我尝试使用makeImage()
on 方法CGContext
但失败了。
此外,打印前内容的定位也存在更多问题。这是 pdf 的样子
由于CGContext
使用与 SwiftUI 不同的坐标系,因此所有内容都位于屏幕底部。我尝试使用.scaleBy()
,但不幸的是,这并没有改变任何东西。
有人可以提供有关如何正确调整定位以CGContext
与 SwiftUI 坐标系保持一致以及如何进行预览工作的指导吗?
要更改坐标系以使原点位于左上角,请参阅此答案。只需向上翻译上下文,然后垂直翻转即可。
这也将翻转 SwiftUI 视图,因此您应该使用 将其翻转回来
.scaleEffect(y: -1)
。最后,如果您希望
GridView
像在实际应用程序中一样占用所有可用空间,则应将其设置frame
为 PDF 页面的大小。以下是在 macOS 上通过 Preview.app 查看的结果:
Xcode Preview 仅支持 SwiftUI
View
、UIView
和UIViewController
. “PDF 文件”不是这些东西。虽然您可以将其转换为图像并在 中显示Image
,但我更喜欢使用PDFView
PDFKit 中的 a :