SwiftUI: loading images with .fileImporter

这一生的挚爱 提交于 2021-01-28 23:53:00

问题


Goal is to load 2 different images (image 1 and 2) with the new .fileImporter modifier.

Problem is I get the same image loaded to both thumbnails (image 1 and 2).

Have anyone managed to do that with .fileImporter modifier?

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()
    }
}

回答1:


Well... I would move file importer into separated view to use binding depending on which button tapped.

Update: worked variant for Form. Tested with 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)
            }
        }
    }
}

Here is possible solution (kept just in case), but not for 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)
            }
        }
    }
}



回答2:


This solution works for 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
        }
    }
}


来源:https://stackoverflow.com/questions/64974785/swiftui-loading-images-with-fileimporter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!