SwiftUI:使用 .fileImporter 加载图像
SwiftUI: loading images with .fileImporter
目标是使用新的 .fileImporter 修饰符加载 2 个不同的图像(图像 1 和 2)。
问题是我将相同的图像加载到两个缩略图(图像 1 和 2)。
有没有人设法用 .fileImporter 修饰符做到这一点?
import SwiftUI
struct ContentView: View {
@State var openFile = false
@State var img1 = UIImage()
@State var img2 = UIImage()
@State var fileName = ""
var body: some View {
Form {
//image 1
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
//image 2
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
}
.navigationTitle("File Importer")
//file importer
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
self.fileName = fileUrl.lastPathComponent
fileUrl.startAccessingSecurityScopedResource()
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.img1 = image
self.img2 = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
好吧...我会将文件导入器移动到单独的视图中,以根据点击的按钮使用绑定。
更新:Form
的工作变体。使用 Xcode 12.1 / iOS 14.1
测试
struct ContentView: View {
@State private var openFile = false
@State private var img1 = UIImage()
@State private var img2 = UIImage()
@State private var target: Binding<UIImage>? // dynamic target for importer
var body: some View {
Form {
//image 1
Button(action: {
self.target = $img1
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
//image 2
Button(action: {
self.target = $img2
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
}
.navigationTitle("File Importer")
//file importer
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.target?.wrappedValue = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
这是可能的解决方案(以防万一),但不适用于 Form
:
struct ImportContentView: View {
@State var openFile = false
@State var img1 = UIImage()
@State var img2 = UIImage()
var body: some View {
//Form { // << does not work for Form !!
VStack {
//image 1
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
.background(LoaderView(isActive: $openFile, image: $img1))
}
//image 2
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
.background(LoaderView(isActive: $openFile, image: $img2))
}
}
.navigationTitle("File Importer")
}
}
struct LoaderView: View {
@Binding var isActive: Bool
@Binding var image: UIImage
var body: some View {
Color.clear
.fileImporter(isPresented: $isActive, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.image = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
此解决方案适用于 Form。
struct FileImporterView: View {
@State var openFile = false
@State var images = [UIImage(), UIImage()]
@State var index = 0
var body: some View {
Form {
ForEach(Array(0..<images.count), id: \.self) { id in
Button(action:{}) {
ImageRow(isPresenting: $openFile, img: $images[id], index: $index, id: id)
}
}
}
.navigationTitle("File Importer")
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image], onCompletion: importImage)
}
func importImage(_ res: Result<URL, Error>) {
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.images[index] = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
struct ImageRow: View {
@Binding var isPresenting: Bool
@Binding var img: UIImage
@Binding var index: Int
var id: Int
init(isPresenting: Binding<Bool>, img: Binding<UIImage>, index: Binding<Int>, id: Int) {
self._isPresenting = isPresenting
self._img = img
self._index = index
self.id = id
}
var body: some View {
HStack {
Image(uiImage: img)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
self.index = id
self.isPresenting = true
}
}
}
目标是使用新的 .fileImporter 修饰符加载 2 个不同的图像(图像 1 和 2)。
问题是我将相同的图像加载到两个缩略图(图像 1 和 2)。
有没有人设法用 .fileImporter 修饰符做到这一点?
import SwiftUI
struct ContentView: View {
@State var openFile = false
@State var img1 = UIImage()
@State var img2 = UIImage()
@State var fileName = ""
var body: some View {
Form {
//image 1
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
//image 2
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
}
.navigationTitle("File Importer")
//file importer
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
self.fileName = fileUrl.lastPathComponent
fileUrl.startAccessingSecurityScopedResource()
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.img1 = image
self.img2 = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
好吧...我会将文件导入器移动到单独的视图中,以根据点击的按钮使用绑定。
更新:Form
的工作变体。使用 Xcode 12.1 / iOS 14.1
struct ContentView: View {
@State private var openFile = false
@State private var img1 = UIImage()
@State private var img2 = UIImage()
@State private var target: Binding<UIImage>? // dynamic target for importer
var body: some View {
Form {
//image 1
Button(action: {
self.target = $img1
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
//image 2
Button(action: {
self.target = $img2
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
}
}
.navigationTitle("File Importer")
//file importer
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.target?.wrappedValue = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
这是可能的解决方案(以防万一),但不适用于 Form
:
struct ImportContentView: View {
@State var openFile = false
@State var img1 = UIImage()
@State var img2 = UIImage()
var body: some View {
//Form { // << does not work for Form !!
VStack {
//image 1
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img1)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
.background(LoaderView(isActive: $openFile, image: $img1))
}
//image 2
Button(action: {
self.openFile.toggle()
}){
Image(uiImage: self.img2)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
.background(LoaderView(isActive: $openFile, image: $img2))
}
}
.navigationTitle("File Importer")
}
}
struct LoaderView: View {
@Binding var isActive: Bool
@Binding var image: UIImage
var body: some View {
Color.clear
.fileImporter(isPresented: $isActive, allowedContentTypes: [.image]) { (res) in
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.image = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
}
此解决方案适用于 Form。
struct FileImporterView: View {
@State var openFile = false
@State var images = [UIImage(), UIImage()]
@State var index = 0
var body: some View {
Form {
ForEach(Array(0..<images.count), id: \.self) { id in
Button(action:{}) {
ImageRow(isPresenting: $openFile, img: $images[id], index: $index, id: id)
}
}
}
.navigationTitle("File Importer")
.fileImporter(isPresented: $openFile, allowedContentTypes: [.image], onCompletion: importImage)
}
func importImage(_ res: Result<URL, Error>) {
do{
let fileUrl = try res.get()
print(fileUrl)
guard fileUrl.startAccessingSecurityScopedResource() else { return }
if let imageData = try? Data(contentsOf: fileUrl),
let image = UIImage(data: imageData) {
self.images[index] = image
}
fileUrl.stopAccessingSecurityScopedResource()
} catch{
print ("error reading")
print (error.localizedDescription)
}
}
}
struct ImageRow: View {
@Binding var isPresenting: Bool
@Binding var img: UIImage
@Binding var index: Int
var id: Int
init(isPresenting: Binding<Bool>, img: Binding<UIImage>, index: Binding<Int>, id: Int) {
self._isPresenting = isPresenting
self._img = img
self._index = index
self.id = id
}
var body: some View {
HStack {
Image(uiImage: img)
.renderingMode(.original)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
self.index = id
self.isPresenting = true
}
}
}