PHPickerとは
WWDC2020で新しいImagePickerが発表されました。
UIImagePickerControllerに代わる新しいデフォルトのImagePickerです。
検索ができたりアクセス権限を求めないなど今までとは違った挙動ですが詳細は省きます。
動作環境
macOS 10.15.6
Xcode 12 beta 1
iOS 14 beta 1
使い方
// Pickerの設定
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
// Pickerで選択するメディアの種類をフィルタリング
config.filter = .images // videos, livePhotos
// 選択できる数を指定
config.selectionLimit = 3
// configを渡して初期化
let controller = PHPickerViewController(configuration: configuration)
// delegateをセット
controller.delegate = self
// 表示
present(controller, animated: true)
config.filter
でPickerに表示されるメディアを選択できます。
現時点で .images
, videos
, livePhotos
が確認できました。
config.selectionLimit
でPickerで選択できる数値を決められます。
便利ですね。
PHPickerViewControllerDelegateの設定
extension ViewController: PHPickerViewControllerDelegate {
// Pickerを閉じたときにコールされる
public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
for image in results {
// PHPickerResultからImageを読み込む
image.itemProvider.loadObject(ofClass: UIImage.self) { (selectedImage, error) in
if let error = error {
print("error: \(error.localizedDescription)")
return
}
// UIImageに変換
guard let wrapImage = selectedImage as? UIImage else {
print("wrap error")
return
}
// 選択されたimageを保管しておく
self.selectedImages.append(wrapImage)
}
}
}
}
SwiftUIでの使用方法
import SwiftUI
import PhotosUI
struct ImageSelectView: View {
// Pickerの表示/非表示フラグ
@State private var isPresented = false
// Imageを格納
@State var pickerResult = UIImage(named: "defaultImage")!
// PHPickerの設定
var config: PHPickerConfiguration {
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
config.filter = .images
config.selectionLimit = 1
return config
}
var body: some View {
VStack(alignment: .leading) {
Button("Image Picker") {
// isPresentedを切り替える
isPresented.toggle()
}.sheet(isPresented: $isPresented) {
// Pickerを初期化
PhotoPicker(configuration: self.config,
pickerResult: $pickerResult,
isPresented: $isPresented)
}
// 選択したImageを表示する
Image.init(uiImage: pickerResult)
.renderingMode(.original)
.resizable()
.frame(width: UIScreen.main.bounds.width, height: 250, alignment: .center)
.scaledToFill()
}
}
}
// PHPickerViewControllerをSwiftUIで表示するためのクラス
// 参考 https://dev.classmethod.jp/articles/tried-swiftui-tutorial-secondpart/
struct PhotoPicker: UIViewControllerRepresentable {
let configuration: PHPickerConfiguration
@Binding var pickerResult: UIImage
@Binding var isPresented: Bool
func makeUIViewController(context: Context) -> PHPickerViewController {
let controller = PHPickerViewController(configuration: configuration)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
/// PHPickerViewControllerDelegate => Coordinator
class Coordinator: PHPickerViewControllerDelegate {
private let parent: PhotoPicker
init(_ parent: PhotoPicker) {
self.parent = parent
}
// PHPickerViewControllerDelegateの設定
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
for image in results {
image.itemProvider.loadObject(ofClass: UIImage.self) { (selectedImage, error) in
if let error = error {
print("error: \(error.localizedDescription)")
return
}
guard let wrapImage = selectedImage as? UIImage else {
print("wrap error")
return
}
// 選択したImageをpickerResultに格納
self.parent.pickerResult = wrapImage
}
}
// 閉じる
parent.isPresented = false
}
}
}
UIKitをSwiftUIで使えるようにするためひと手間必要でした