SwiftUI-照片选择器

2,381 阅读1分钟

通过SwiftUI 的 PhotosPicker 视图 ,我们从用户照片库导入一张或多张照片。为了避免造成任何性能问题,数据以一种名为PhotosPickerItem 的特殊类型提供给我们,然后我们可以异步加载该类型,以将数据转换为 SwiftUI 图像。

单选

这总共需要五个步骤:

  1. 导入框架
import PhotosUI
import SwiftUI  

2.其次,创建两个属性:一个用于存储所选项目,另一个用于将该项目存储为 SwiftUI 图像。

@State private var pickerItem: PhotosPickerItem?
@State private var selectedImage: Image?  

这种区别很重要,因为在我们实际要求加载之前,所选项目只是对用户照片库中图片的引用。

3.在 SwiftUI 视图层次结构中的某个位置添加一个PhotosPicker 视图

VStack {
    PhotosPicker("选择照片", selection: $pickerItem, matching: .images)
}  
  1. 观察pickerItem变化,因为当它变化时,意味着用户已经选择了一张图片供我们加载。
VStack {
    PhotosPicker("选择照片", selection: $pickerItem, matching: .images)
}  
.onChange(of: pickerItem) { 
    Task { 
        selectedImage = try await pickerItem?.loadTransferable(type: Image.self) 
    }
}  

加载完成后,我们可以调用loadTransferable(type:)选择器项,该方法告诉 SwiftUI 我们想要将实际的底层数据,从选择器项加载到 SwiftUI 图像中。如果成功,我们可以将结果值分配给该selectedImage属性。

调用loadTransferable(type:)可能需要几秒钟才能完成,特别是对于全景图等大图片。

  1. 在某处显示加载的 SwiftUI 图像
selectedImage? 
    .resizable() 
    .scaledToFit()  

多选

@State private var pickerItems = [PhotosPickerItem]()  
@State private var selectedImages = [Image]()  

...

VStack {
    PhotosPicker("选择照片", selection: $pickerItems, maxSelectionCount: 3, matching: .images)  
}   

处理选择结果

.onChange(of: pickerItems) {
    Task {
        selectedImages.removeAll()

        for item in pickerItems {
            if let loadedImage = try await item.loadTransferable(type: Image.self){
                selectedImages.append(loadedImage)
            }
        }
    }
}  

显示选择的图片

ScrollView {
    ForEach(0..<selectedImages.count, id: \.self) { i in
        selectedImages[i]
            .resizable()
            .scaledToFit()
    }
}  

另外,可以提供完全自定义的标签

PhotosPicker(selection: $pickerItems, maxSelectionCount: 3, matching: .images) { 
    Label("选择照片", systemImage: "photo")
}  

限制可以导入的图片种类

.images在这里全面使用,这意味着我们将获得常规照片、屏幕截图、全景图等。您可以使用.any()、.all()和来应用更高级的过滤器.not(),并向它们传递一个数组。

PhotosPicker(selection: $pickerItems, maxSelectionCount: 3, matching: .any(of: [.images, .not(.screenshots)])) {
    Label("Select a picture", systemImage: "photo")
}