iOS 16 中的改进功能。
ImageRenderer
类能够将任何 SwiftUI 视图层次结构渲染为图像,然后可以以其他方式保存、共享或重用该图像。
// 最简单的,所需的代码是这样的:
let renderer = ImageRenderer(content: Text("Hello, world!"))
if let uiImage = renderer.uiImage {
// use the rendered image somehow
}
这里有四个关键点需要注意:
ImageRenderer
,这意味着需要用 @MainActor
标记渲染代码ImageRenderer(content:)
初始值设定项中,但将它们分离到专用视图中会让代码更清晰UIGraphicsImageRenderer
不同,没有简单的方法可以直接从 ImageRenderer
读取 PNG 或 JPEG 数据;因此正如在代码中看到的,我们需要读取其结果的 UIImage
方法。这使得跨平台用户的代码更加复杂第二个示例,它会自动使用设备的正确图像比例,使用 @MainActor
确保渲染代码可以安全调用,将视图渲染到它自己的结构中,然后让用户使用 ShareLink
共享结果:
// 将要用于生成图片的视图
struct RenderView: View {
let text: String
var body: some View {
Text(text)
.font(.largeTitle)
.foregroundStyle(.white)
.padding()
.background(.blue)
.clipShape(Capsule())
}
}
struct ContentView: View {
@State private var text = "Your text here"
@State private var renderedImage = Image(systemName: "photo")
// 获取设备的屏幕显示倍数,后面用于生成
@Environment(\\.displayScale) var displayScale
var body: some View {
VStack {
renderedImage
ShareLink(
"Export",
item: renderedImage,
preview: SharePreview(Text("Shared image"), image: renderedImage)
)
TextField("Enter some text", text: $text)
.textFieldStyle(.roundedBorder)
.padding()
}
// 当显示视图时以及每当 text 发生变化时,都会调用渲染方法
.onChange(of: text) { _ in
render()
}
.onAppear {
render()
}
}
// 执行渲染方法:
@MainActor func render() {
let renderer = ImageRenderer(content: RenderView(text: text))
// 使用设备的显示倍数去渲染生成图片
renderer.scale = displayScale
if let uiImage = renderer.uiImage {
renderedImage = Image(uiImage: uiImage)
}
}
}
iOS 16 中的改进功能。
ImageRenderer
类可以将任何 SwiftUI 视图渲染为 PDF,是的:所有文本和形状仍然是矢量,因此它们可以完美地缩放。
使用 ImageRenderer
创建 PDF 需要八个步骤:
render()
方法来启动渲染代码CGContext
对象来处理 PDF 页面完成后,您将获得 PDF 的 URL地址,并且可以随意使用
这听起来工作量很大,下面是一个完整的示例,它使用 ShareLink
将视图呈现为要导出的 PDF,其中的注释与上面的说明相匹配:
@MainActor
struct ContentView: View {
var body: some View {
ShareLink("Export PDF", item: render())
}
func render() -> URL {
// 1: Render Hello World with some modifiers
let renderer = ImageRenderer(content:
Text("Hello, world!")
.font(.largeTitle)
.foregroundStyle(.white)
.padding()
.background(.blue)
.clipShape(Capsule())
)
// 2: Save it to our documents directory
let url = URL.documentsDirectory.appending(path: "output.pdf")
// 3: Start the rendering process
renderer.render { size, context in
// 4: Tell SwiftUI our PDF should be the same size as the views we're rendering
var box = CGRect(x: 0, y: 0, width: size.width, height: size.height)
// 5: Create the CGContext for our PDF pages
guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
return
}
// 6: Start a new PDF page
pdf.beginPDFPage(nil)
// 7: Render the SwiftUI view data onto the page
context(pdf)
// 8: End the page and close the file
pdf.endPDFPage()
pdf.closePDF()
}
return url
}
}