使用 PhotosPicker 轻松从照片库添加图片
SwiftUI 的 PhotosPicker 组件使得从用户照片库中选择并添加图片变得简单而高效。本文将逐步指导您如何在 SwiftUI 应用中实现这一功能,提升用户体验。
在开发过程中,您可能会遇到需要从用户的照片库中选择图片的情况。为此,SwiftUI 提供了一个非常方便的组件——PhotosPicker。
什么是 PhotosPicker
PhotosPicker 实在 iOS 16 和 iPadOS 16 中引入的一个新组件,旨在简化用户从照片库中选择图片的过程,开发者无需手动处理照片选择的逻辑。PhotosPicker 提供了一个简洁且功能强大的接口,能够轻松集成到 SwiftUI 应用中。
为什么使用 PhotosPicker
之前的版本中,开发者通常需要依赖 UIKit 的 UIImagePickerController
来实现类似功能,这个过程需要引入 UIKit 组件,并且开发者需要管理复杂的状态和界面更新逻辑,增加了混合框架编程的复杂性。
使用 PhotosPicker 的主要优势在于它与 SwiftUI 的深度集成,使用更少的代码实现照片选择功能,同时保持与系统原生外观一致。此外,PhotosPicker 还提供了更灵活的配置选项,允许开发者轻松指定允许的媒体类型,如仅选择图片或视频等。
如何使用 PhotosPicker 组件
基本用法
在使用 PhotosPicker 之前,首先需要在项目中导入 PhotosUI 框架,这个框架包含了所有与照片选择相关的功能,未默认包含在 SwiftUI 框架中。
import PhotosUI
接下来,我们创建一个 PhotosPickerItem
类型的新变量来存储所选图像。
import SwiftUI
import PhotosUI
struct PhotosPickerView: View {
@State private var avatarPhotoItem: PhotosPickerItem?
var body: some View {
VStack {
PhotosPicker(
"选择图片",
selection: $avatarPhotoItem)
}
}
}
添加图片预览 / loadTransferable
PhotosPicker 不会自动处理显示,因此我们可以手动为它添加显示。从 PhotosPicker 中获取到的数据是 Data 类型,而 SwiftUI 的 Image 组件没有直接处理 Data 的构造函数,因此无法直接使用 Image() 组件来显示。
loadTransferable
是 photoKit 提供,可以用于从PhotosPickerItem
中加载和转换用户选择的媒体数据。非常适合处理可能需要从系统文件或资源中异步加载数据的场景,比如从照片库中提取图片。
import PhotosUI
import SwiftUI
struct PhotosPickerView: View {
@State private var avatarPhotoItem: PhotosPickerItem?
@State private var selectedImage: Image?
var body: some View {
VStack(spacing: 16) {
// 显示选中的图片预览
if let selectedImage = selectedImage {
selectedImage
.resizable()
.scaledToFill()
.frame(width: 100, height: 100)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
}
// 当用户未选择头像时显示“选择头像”,选择后显示“更换头像”
let buttonText = selectedImage == nil ? "选择头像" : "更换头像"
PhotosPicker(
buttonText, selection: $avatarPhotoItem, matching: .images)
}
.padding()
.task(id: avatarPhotoItem) {
// 使用新的方式加载和转换图片
if let avatarPhotoItem = avatarPhotoItem {
if let data = try? await avatarPhotoItem.loadTransferable(
type: Data.self),
let uiImage = UIImage(data: data)
{
selectedImage = Image(uiImage: uiImage)
}
}
}
}
}
struct PhotosPicker_Previews: PreviewProvider {
static var previews: some View {
PhotosPickerView()
}
}
它是异步的,使用 Swift 的 async/await
语法,确保在加载较大文件时不会阻塞主线程,提升应用的响应速度和用户体验。
过滤媒体类型 / matching
PhotosPicker 提供了可选的matching
参数,用于过滤用户可以从照片库中选择的媒体类型。
下面这个代码,限制用户只能选择视频类型:
import PhotosUI
import SwiftUI
struct PhotosPickerView: View {
@State private var avatarPhotoItem: PhotosPickerItem?
var body: some View {
VStack {
PhotosPicker(
"选择视频",
selection: $avatarPhotoItem,
matching: .videos)
}
}
}
struct PhotosPicker_Previews: PreviewProvider {
static var previews: some View {
PhotosPickerView()
}
}
matching 提供了多个预设的类型供选择,并且支持灵活组合使用:
.any(of: [PHPickerFilter])
允许用户选择多种类型的媒体。比如,允许选择图片或视频:
matching: .any(of: [.images, .videos])
.not(PHPickerFilter)
:排除特定类型的媒体。比如,不允许选择图片:
matching: .not(.images)
.livePhotos
:仅允许选择实况照片。
matching: .livePhotos
.videos
:仅允许选择视频。
matching: .videos
.images
:仅允许选择图片。
matching: .images
通过编程方式调用 .photosPicker
PhotosPicker 组件在 SwiftUI 中非常实用,能够方便用户从照片库中选择图片。然而,它是通过 UI 触发的,也就是说,必须由用户点击一个 Button
或其他触发器来打开选择器。
然而,在某些场景下,你可能希望在符合特定条件时,自动触发 PhotosPicker
,而无需用户手动点击。例如,当用户首次打开应用时,如果他们还没有设置头像,你可能希望自动打开照片选择器,提示他们选择一张照片。
在这种情况下,你可以使用 .photosPicker
修饰器,并结合一个绑定到 Bool
类型的状态变量来控制选择器的显示。通过这种方式,选择器可以在编程条件满足时自动弹出,而不是依赖用户的手动操作。
官方文档中的 .photosPicker
用法如下:
.photosPicker(isPresented: $shouldShowPicker, selection: $selectedItems, matching: .images)
此外,你可以使用 .onChange
修饰器来监控 selectedItems
的变化,并在用户选择图片后,自动执行一些操作,比如加载和显示选中的图片。使用示例如下:
import SwiftUI
import PhotosUI
struct ContentView: View {
@State private var shouldShowPicker = false
@State private var selectedItems: [PhotosPickerItem] = []
@State private var selectedImage: UIImage?
var body: some View {
VStack {
if let image = selectedImage {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
} else {
Text("没有选择图片")
.foregroundColor(.gray)
}
Button("选择图片") {
shouldShowPicker = true
}
}
.photosPicker(isPresented: $shouldShowPicker, selection: $selectedItems, matching: .images)
.onChange(of: selectedItems) { newItems in
Task {
if let firstItem = newItems.first,
let data = try? await firstItem.loadTransferable(type: Data.self),
let uiImage = UIImage(data: data) {
selectedImage = uiImage
}
}
}
.onAppear {
// 示例场景:当视图首次出现时,自动打开选择器
if selectedImage == nil {
shouldShowPicker = true
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
更多开发文章: