ハイライト
iOS 14 では新しい写真ピッカーが導入されています (
PHPickerViewController)、以前のものを置き換えますUIImagePickerControllerアルバムのアクセス許可を手動でリクエストしてから使用しますPHAssetフィルタリング方法。
主要内容
多くのアプリは、アバターを変更する、チャット メッセージに写真を添付する、エディタに数枚の写真をインポートするなど、小さなタスクのみを完了したいと考えています。以前は、フォト ギャラリーの完全なアクセス許可をリクエストしてから、PhotoKitまたは古いUIImagePickerController写真を持ち込んでください。この権限の範囲は広すぎます。ユーザーは「写真を選択」を 1 回クリックするだけですが、アプリは写真ライブラリ全体にアクセスできる場合があります。
iOS14PHPickerViewControllerこのプロセスをシステム エージェントに変更します。セレクターはシステムによって提供され、アプリの外部の別のプロセスで実行されます。アプリはセレクター内の他のコンテンツを参照したり、セレクター インターフェイスをインターセプトしたりすることはできません。ユーザーが選択した写真とビデオのみが結果としてアプリに返されます。 (01:06)
この変更により、古いセレクターのエクスペリエンスの問題も解決されます。新しい写真ピッカーには、システムの写真アプリと同じグリッド、検索、ズーム、複数選択、選択したコンテンツのプレビューが備わっています。開発者は構成オブジェクトを使用してオプションの種類と選択肢の数を制限し、デリゲートを通じて結果を受け取ります。 (00:24)
Apple が与えた境界は明確です。写真またはビデオ データのみを必要とするほとんどのアプリは、直接使用する必要はありませんPhotoKit。画像の非破壊編集や写真ライブラリの整理など、必要な作業のみPHAssetアプリはフォト ライブラリのアクセス許可を要求し、iOS 14 の限定されたフォト ライブラリを処理する必要があります。 (10:15)
詳細
選択範囲と複数選択の数を構成する
(02:27)PHPickerConfiguration入り口です。これは、ユーザーが選択できる項目の最大数とセレクターに表示できるメディア タイプという 2 つの重要な決定を制御します。
import PhotosUI
var configuration = PHPickerConfiguration()
// “unlimited” selection by specifying 0, default is 1
configuration.selectionLimit = 0
// Only show images (including Live Photos)
configuration.filter = .images
// Uncomment next line for other example: Only show videos or Live Photos (for their video complement), but no images
// configuration.filter = .any(of: [.videos, .livePhotos])
キーポイント:
import PhotosUI写真ピッカーが配置されているフレームを紹介します。PHPickerConfiguration()ここに可変設定オブジェクトを作成し、その後の選択番号やフィルター条件を記述します。selectionLimitデフォルトは 1 です。無制限の複数選択の場合は 0 に設定します。.imagesLive Photosを含む写真が表示されます。.any(of: [.videos, .livePhotos])これは、公式スニペットの別のフィルターの例で、ビデオと Live Photos のビデオ部分を表示するために使用されます。
ピッカーをレンダリングして結果を受け取る
(03:07) 設定が完了したら、それを使用して初期化しますPHPickerViewController。アプリ自体がピッカーの表示と終了を担当します。ユーザーが確認した後、デリゲートは[PHPickerResult]。
import UIKit
import PhotosUI
class SingleSelectionPickerViewController: UIViewController, PHPickerViewControllerDelegate {
@IBAction func presentPicker(_ sender: Any) {
var configuration = PHPickerConfiguration()
// Only wants images
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
// The client is responsible for presentation and dismissal
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// The client is responsible for presentation and dismissal
picker.dismiss(animated: true)
// Get the first item provider from the results, the configuration only allowed one image to be selected
let itemProvider = results.first?.itemProvider
if let itemProvider = itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self) {
itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in
// TODO: Do something with the image or handle the error
}
} else {
// TODO: Handle empty results or item provider not being able load UIImage
}
}
}
キーポイント:
- コントローラーは以下に準拠する必要があります。
PHPickerViewControllerDelegateそうでない場合、ユーザーの選択結果は受信されません。 PHPickerViewController(configuration:)以前の構成をシステム セレクター インターフェイスに変えます。picker.delegate = self現在のコントローラーが選択完了コールバックを受信することを指定します。didFinishPickingのresults空の場合もあります。これは、ユーザーが選択を解除したときに発生します。PHPickerResult合格itemProviderデータ表現を提供し、ロードする前にそれを使用しますcanLoadObject(ofClass:)タイプを確認してください。loadObject(ofClass:)非同期APIです。エラーはコールバックで処理する必要があり、UI の更新はメイン スレッドに切り替える必要があります。
複数の選択が行われた場合にオンデマンドで画像をロードします
(07:34) 複数選択では、すべての画像を一度にメモリにロードする必要はありません。デモアプリは返されたもののみを保存しますNSItemProvider、イテレータを使用して次のイメージをオンデマンドでロードします。
import UIKit
import PhotosUI
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
var itemProviders: [NSItemProvider] = []
var iterator: IndexingIterator<[NSItemProvider]>?
@IBAction func presentPicker(_ sender: Any) {
var configuration = PHPickerConfiguration()
configuration.filter = .images
configuration.selectionLimit = 0
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)
}
func displayNextImage() {
if let itemProvider = iterator?.next(), itemProvider.canLoadObject(ofClass: UIImage.self) {
let previousImage = imageView.image
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
DispatchQueue.main.async {
guard let self = self, let image = image as? UIImage, self.imageView.image == previousImage else { return }
self.imageView.image = image
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
displayNextImage()
}
}
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true)
itemProviders = results.map(\.itemProvider)
iterator = itemProviders.makeIterator()
displayNextImage()
}
}
キーポイント:
selectionLimit = 0無制限の複数選択がオンになっている場合、ピッカーには複数選択に適したインターフェイスと [追加] ボタンが表示されます。itemProvidersデータ プロバイダーの参照のみを保存し、事前にすべてのイメージをデコードしないでください。iterator現在の表示の進行状況を記録します。displayNextImage()一度に処理されるのは次のアイテムのみです。previousImageそしてguard非同期コールバックが変更を上書きするのを防ぐために使用されますimageView。touchesEndedデモでは次の画像に切り替えるために使用されており、実際のアプリでは同じロジックをボタン、ページネーション、またはサムネイル リストに適用できます。results.map(\.itemProvider)すべての選択結果を、後でロード可能なデータ ソースに変換します。
PHAsset が必要な場合は PhotoKit に再度接続します
(11:13) いくつかのアプリは引き続き使用する必要がありますPhotoKit、非破壊編集や写真ライブラリの整理など。現時点で使用可能PHPhotoLibrary構成を初期化し、結果でそれを読み取りますassetIdentifier、次に標準を使用しますPhotoKit API fetch PHAsset。
import UIKit
import PhotosUI
class PhotoKitPickerViewController: UIViewController, PHPickerViewControllerDelegate {
@IBAction func presentPicker(_ sender: Any) {
let photoLibrary = PHPhotoLibrary.shared()
let configuration = PHPickerConfiguration(photoLibrary: photoLibrary)
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
let identifiers = results.compactMap(\.assetIdentifier)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
// TODO: Do something with the fetch result if you have Photos Library access
}
}
キーポイント:
PHPhotoLibrary.shared()現在のフォト ライブラリ オブジェクトを取得し、それを使用してオブジェクトを構成します。PhotoKit位置合わせ。PHPickerConfiguration(photoLibrary:)それは必要ですPHAsset識別子に使用される初期化メソッド。results.compactMap(\.assetIdentifier)ローカル資産識別子を含まない結果をフィルターで除外します。PHAsset.fetchAssets(withLocalIdentifiers:options:)識別子を次のように変換しますPHAssetクエリ結果。- このコメントは、許可の前提条件を強調しています。すでに写真ライブラリへのアクセス権を持っているアプリのみが、フェッチ結果に対して後続の処理を実行できます。
- ユーザーがピッカーでさらに写真を選択しても、限定された写真ライブラリは自動的に拡張されません
PHAssetアクセス可能な範囲。追加の許可が必要な場合は、専用の限定されたライブラリ管理プロセスを使用する必要があります。
重要ポイント
- 対処方法: アバターのアップロードを 1 回限りの写真ピッカーに変更します
これを行う価値がある理由: アバターをアップロードするのに必要な写真は 1 枚だけです。最初に写真ライブラリ全体の許可を求める必要はありません。PHPickerViewControllerユーザーが写真を直接選択できるようにすると、アプリはこの選択の結果のみを取得します。
開始方法: 作成するPHPickerConfiguration()、設定configuration.filter = .images、デフォルトのままにしますselectionLimit = 1、存在するdidFinishPicking合格itemProvider.loadObject(ofClass: UIImage.self)写真を読んでください。
- 対処方法: チャット アプリやメモアプリに複数の画像挿入を追加します
実行する価値がある理由: このセッションでは、ピッカーの複数選択、選択プレビュー、および [追加] ボタンが表示され、ユーザーは一度に写真のグループを選択できます。
開始方法:configuration.selectionLimit0 または製品で許可されている数量に設定します。コールバックに保存するresults.map(\.itemProvider)、メッセージの送信順または挿入順に 1 つずつ読み込まれます。
- やるべきこと: 画像エディター用に低権限のインポート エントリを作成します
価値がある理由: 多くの編集者は、写真ライブラリ全体を参照することなく、ユーザーが現在選択している画像データのみを必要とします。ピッカーによって返されましたNSItemProviderすでにロード可能ですUIImage。
開始方法: 最初に使用しますPHPickerViewControllerデフォルトのインポートを実行します。高度な機能が本当に追跡したい場合PHAsset、機能の入り口でフォト ライブラリへのアクセスをリクエストします。
- やるべきこと: 写真ライブラリ整理アプリ用の PhotoKit フォークを作成します
実行する価値がある理由: フォト アルバムの整理や非破壊編集などのアプリが必要ですPHAssetとフォトギャラリーのアクセス状況。セッションはピッカーから取得した結果を返しますassetIdentifierもう一度取ってくるPHAssetパス。
開始方法: を使用しますPHPickerConfiguration(photoLibrary:)セレクターを初期化します。コールバックで収集するassetIdentifier;ユーザーが写真ライブラリへのアクセスを許可したかどうかを検出します。拡張する必要があるPHAssetスコープにアクセスするときは、セッションで説明されている追加の承認プロセスにアクセスします。
関連セッション
- アプリで制限付き写真ライブラリを処理する — iOS 14 の制限付き写真ライブラリと、PhotoKit アプリを PHPicker に切り替える必要があるタイミングについて説明します。
- プライバシーの向上による信頼の構築 - 権限、透明性、ユーザー制御の観点から iOS 14 のプライバシー設計を説明します。
- iOS ピッカー、メニュー、アクションを使用して構築 — UIKit の新しいピッカー、メニュー、およびアクション コントロールを紹介します。システムの写真選択の入り口と合わせて理解するのに適しています。
- iOS ピッカー、メニュー、アクションを使用した設計 — どのような対話シナリオのピッカー、メニュー、アクションを配置する必要があるかを設計の観点から説明します。
コメント
GitHub Issues · utterances