xcode - SwiftUI:.fileExporter 仅导出 1 个文档
问题描述
平台和版本 iOS Xcode 版本 12.4 (12D4e)
目标:使用 SwiftUI .fileExporter 修饰符导出多个图像。
问题:在使用 NS Image 的 MacOS 上,所有图像都被导出。在使用 UIImage 的 iOS(iPad、Catalyst 和 iPhone)上,仅导出 1 个图像
重现步骤
iOS 代码:
import SwiftUI
class AppContext: ObservableObject {
@Published var fileSaveDialogShown = false
}
@main
struct ExportApp: App {
@StateObject var appContext = AppContext()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.appContext)
.fileExporter(
isPresented: $appContext.fileSaveDialogShown,
documents: [
ImageDocument(image: UIImage(named: "1")),
ImageDocument(image: UIImage(named: "2"))
],
contentType: .png // Match this to your representation in ImageDocument
) { url in
print("Saved to", url) // [URL]
}
}
}
}
import SwiftUI
import UniformTypeIdentifiers
struct ImageDocument: FileDocument {
static var readableContentTypes: [UTType] { [.jpeg, .png, .tiff] }
var image: UIImage
init(image: UIImage?) {
self.image = image ?? UIImage()
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let image = UIImage(data: data)
else {
throw CocoaError(.fileReadCorruptFile)
}
self.image = image
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
// You can replace tiff representation with what you want to export
return FileWrapper(regularFileWithContents: image.pngData()!)
}
}
struct ContentView: View {
@EnvironmentObject var appContext: AppContext
var body: some View {
VStack {
Button(action: {
appContext.fileSaveDialogShown.toggle()
}, label: {
Text("Button")
})
}
.frame(width: 200, height: 200)
}
}
MacOS code:
import SwiftUI
class AppContext: ObservableObject {
@Published var fileSaveDialogShown = false
}
@main
struct FocalApp: App {
@StateObject var appContext = AppContext()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.appContext)
.fileExporter(
isPresented: $appContext.fileSaveDialogShown,
documents: [
ImageDocument(image: NSImage(named: "1")),
ImageDocument(image: NSImage(named: "2"))
],
contentType: .jpeg // Match this to your representation in ImageDocument
) { url in
print("Saved to", url) // [URL]
}
}
}
}
import SwiftUI
import UniformTypeIdentifiers
struct ImageDocument: FileDocument {
static var readableContentTypes: [UTType] { [.jpeg, .png, .tiff] }
var image: NSImage
init(image: NSImage?) {
self.image = image ?? NSImage()
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let image = NSImage(data: data)
else {
throw CocoaError(.fileReadCorruptFile)
}
self.image = image
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
// You can replace tiff representation with what you want to export
return FileWrapper(regularFileWithContents: image.tiffRepresentation!)
}
}
struct ContentView: View {
@EnvironmentObject var appContext: AppContext
var body: some View {
VStack {
Button(action: {
appContext.fileSaveDialogShown.toggle()
}, label: {
Text("Button")
})
}
.frame(width: 200, height: 200)
}
}
解决方案
您似乎需要为每个导出的文件提供唯一的名称。如果没有明确定义名称,两个图像都将被命名为“导出的 PNG 图像”,因此第一个将被覆盖。
这对我有用:
import SwiftUI
class AppContext: ObservableObject {
@Published var fileSaveDialogShown = false
}
@main
struct ExportApp: App {
@StateObject var appContext = AppContext()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.appContext)
.fileExporter(
isPresented: $appContext.fileSaveDialogShown,
documents: [
ImageDocument(image: UIImage(named: "1"), name: "1"),
ImageDocument(image: UIImage(named: "2"), name: "2")
],
contentType: .png // Match this to your representation in ImageDocument
) { url in
print("Saved to", url) // [URL]
}
}
}
}
import SwiftUI
import UniformTypeIdentifiers
struct ImageDocument: FileDocument {
static var readableContentTypes: [UTType] { [.jpeg, .png, .tiff] }
var image: UIImage
var name: String
init(image: UIImage?, name: String) {
self.image = image ?? UIImage()
self.name = name
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let image = UIImage(data: data)
else {
throw CocoaError(.fileReadCorruptFile)
}
self.image = image
self.name = configuration.file.filename ?? "image"
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
// You can replace tiff representation with what you want to export
let fileWrapper = FileWrapper(regularFileWithContents: image.pngData()!)
fileWrapper.filename = self.name
return fileWrapper
}
}
struct ContentView: View {
@EnvironmentObject var appContext: AppContext
var body: some View {
VStack {
Button(action: {
appContext.fileSaveDialogShown.toggle()
}, label: {
Text("Button")
})
}
.frame(width: 200, height: 200)
}
}
推荐阅读
- c++ - for循环中的构造函数问题
- python - Python - 路径/文件夹/文件创建
- python - 为什么不能在计数排序算法中使用哈希表/字典?
- jenkins - 确定 Jenkinsfile 是否从多分支管道运行
- excel - 当A列和B列中相邻单元格的值之和为5时,如何自动为C列中的单元格着色?(Excel-VBA)
- c# - 可执行文件可以作为 blob 触发的 Azure 函数的一部分运行吗?
- python-3.x - MeCab 解析不正确
- java - 如何将 ArrayList 传递给构造函数?
- java - Spring MVC 和 Spring Security 配置的问题
- docker - Docker 服务容器在特定时间间隔后自动重启