从照片库中将多个图像添加到视图中 - SwiftUI

Adding multiple images into a view from photo library - SwiftUI

我想将 phone 照片库中的图片添加到我制作的拼贴布局中。首先,我在 SwiftUI 中将拼贴布局作为一个单独的视图,称为 CollageLayoutOne。

import SwiftUI

struct CollageLayoutOne: View {
    
    var uiImageOne: UIImage
    var uiImageTwo: UIImage
    var uiImageThree: UIImage
    
    var body: some View {
        
        Rectangle()
            .fill(Color.gray)
            .aspectRatio(1.0, contentMode: .fit)
            .overlay {
                HStack {
                    Rectangle()
                        .fill(Color.gray)
                        .overlay {
                            Image(uiImage: uiImageOne)
                                .resizable()
                                .aspectRatio(contentMode: .fill)
                        }
                        .clipped()
                    VStack {
                        Rectangle()
                            .fill(Color.gray)
                            .overlay {
                                Image(uiImage: uiImageTwo)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                            }
                            .clipped()
                        Rectangle()
                            .fill(Color.gray)
                            .overlay {
                                Image(uiImage: uiImageThree)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                            }
                            .clipped()
                    }
                }
                .padding()
            }
    }
}

然后我有一个单独的视图 (PageView),我想在其中显示 CollageLayoutOne 视图,它还包含用于访问图像库的按钮。

struct PageView: View {
    
    @State private var photoPickerIsPresented = false
    @State var pickerResult: [UIImage] = []
    
    var body: some View {
      NavigationView {
        ScrollView {
            if pickerResult.isEmpty {
                
            } else {
                CollageLayoutOne(uiImageOne: pickerResult[0], uiImageTwo: pickerResult[1], uiImageThree: pickerResult[2])
            }
            
            
        }
        .edgesIgnoringSafeArea(.bottom)
        .navigationBarTitle("Select Photo", displayMode: .inline)
        .navigationBarItems(trailing: selectPhotoButton)
        .sheet(isPresented: $photoPickerIsPresented) {
          PhotoPicker(pickerResult: $pickerResult,
                      isPresented: $photoPickerIsPresented)
        }
      }
    }
    
    @ViewBuilder
    private var selectPhotoButton: some View {
      Button(action: {
        photoPickerIsPresented = true
      }, label: {
        Label("Select", systemImage: "photo")
      })
    }
    
}

我的问题是,由于某些未知原因,每次我 select 照片并尝试添加时,应用程序都会崩溃。如果我对所有三个都执行 pickerResult[0] 它工作得很好,但在所有 3 个位置上只显示第一张 selected 照片。此外,如果我将所有 3 个都作为 pickerResult[0] 开始,然后在预览为 运行 时将它们更改为 [0], [1], [2],它不会崩溃并正确显示。

我只是从 Swift 和 SwiftUI 开始,所以请原谅我是否犯了一些基本错误。下面我还添加了我从一篇文章中获得的 PhotoPicker 代码。

PhotoPicker.swift:

import SwiftUI
import PhotosUI

struct PhotoPicker: UIViewControllerRepresentable {
  @Binding var pickerResult: [UIImage]
  @Binding var isPresented: Bool
  
  func makeUIViewController(context: Context) -> some UIViewController {
    var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
    configuration.filter = .images // filter only to images
    if #available(iOS 15, *) {
        configuration.selection = .ordered //number selection
    }
    configuration.selectionLimit = 3 // ignore limit
    
    let photoPickerViewController = PHPickerViewController(configuration: configuration)
    photoPickerViewController.delegate = context.coordinator
    return photoPickerViewController
  }
  
  func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
  
  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }
  
  class Coordinator: PHPickerViewControllerDelegate {
    private let parent: PhotoPicker
    
    init(_ parent: PhotoPicker) {
      self.parent = parent
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
      parent.pickerResult.removeAll()
      
      for image in results {
        if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
          image.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] newImage, error in
            if let error = error {
              print("Can't load image \(error.localizedDescription)")
            } else if let image = newImage as? UIImage {
              self?.parent.pickerResult.append(image)
            }
          }
        } else {
          print("Can't load asset")
        }
      }
      
      parent.isPresented = false
    }
  }
}

image.itemProvider.loadObject为异步函数,一张一张加载图片

处理完第一张图像后,您将其添加到 pickerResult 并且您的 pickerResult.isEmpty 检查变为 false,但是您的数组到目前为止只包含一个项目。

这里安全的做法是检查计数:

if pickerResult.count == 3 {
    CollageLayoutOne(uiImageOne: pickerResult[0], uiImageTwo: pickerResult[1], uiImageThree: pickerResult[2])
}

此外,在这种情况下,最好等到所有异步请求完成后再更新 UI,例如,像这样:

var processedResults = [UIImage]()
var leftToLoad = results.count
let checkFinished = { [weak self] in
    leftToLoad -= 1
    if leftToLoad == 0 {
        self?.parent.pickerResult = processedResults
        self?.parent.isPresented = false
    }
}
for image in results {
    if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
        image.itemProvider.loadObject(ofClass: UIImage.self) { newImage, error in
            if let error = error {
                print("Can't load image \(error.localizedDescription)")
            } else if let image = newImage as? UIImage {
                processedResults.append(image)
            }
            checkFinished()
        }
    } else {
        print("Can't load asset")
        checkFinished()
    }
}