SwiftUI:使用 .fileImporter 加载图像

Posted

技术标签:

【中文标题】SwiftUI:使用 .fileImporter 加载图像【英文标题】:SwiftUI: loading images with .fileImporter 【发布时间】:2020-11-23 19:06:30 【问题描述】:

目标是使用新的 .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()
    

【问题讨论】:

但是你是故意在self.img1 = image; self.img2 = image这样做的……所以呢? 对不起,Asperi... 这样做的想法是:如果让 imageData = 试试?数据(contentsOf:fileUrl),让图像= UIImage(数据:imageData)self.img1=image1让图像=UIImage(数据:imageData)self.img2=image2 这可能不正确....如果您能提供一些帮助,我们将不胜感激! :) 【参考方案1】:

嗯...我会将文件导入器移动到单独的视图中以使用绑定,具体取决于点击的按钮。

更新: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)
            
        
    

【讨论】:

感谢@Asperi!这似乎更合乎逻辑!但文件选择器未在此代码上打开...它对您有用吗? 你是对的 - 从头部发布。该变体在Form 中不起作用(原因不明)。立即查看更新和测试。【参考方案2】:

此解决方案适用于 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
        
    

【讨论】:

以上是关于SwiftUI:使用 .fileImporter 加载图像的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?

tab.py 文件

在页面完成读取EXCEL

python学习------tab补全

在SwiftUI项目中使用UIKit(SwiftUI和UIKit混合开发)

如何在 SwiftUI 中使用 Realm