Привет, Хабр! В этой статье я расскажу про работу с видео, live-фото и отслеживание изменений в галерее с помощью Photos framework. Для лучшего понимания статьи рекомендую ознакомиться с предыдущей статьей.
Для того, чтобы загрузить видео из галереи необходимо задать параметры(опции) запроса — PHVideoRequestOptions.
Далее эти параметры вместе с объектом PHAsset(см. предыдущую статью) передаем в следующую функцию:
После того как получили playerItem, можно его воспроизвести. Для проигрывания видео используется класс AVPlayerLayer и AVPlayer:
Работа с live-фото и видео похожи. Для начала мы также задаем параметры запроса, только теперь с помощью класса PHLivePhotoRequestOptions:
Затем загружаем live-фото:
После получения объекта livePhoto можем отобразить его в специальном компоненте PHLivePhotoView. Этот компонент очень похож на UIImageView. Он предназначен для отображения live-фото.
Photos framework позволяет следить за изменениями, произошедшими как с альбомами так и с отдельными фото или видео. Чтобы начать отслеживать изменения нужно добавить обсервер в PHPhotoLibrary:
Обсервер должен реализовывать протокол PHPhotoLibraryChangeObserver, в котором есть всего один метод — photoLibraryDidChange(_ changeInstance: PHChange). Параметр changeInstance — это объект, который содержит список изменений, произошедших в галерее.
В качестве примера покажу как обновить collectionView в соответствии с произошедшими изменениями.
Приведенный в статьях код не является идеальным. Главная его задача — показать механизм работы Photos framework. Если что-то было непонятно — спрашивайте в комментариях. Возможно, немного позже сделаю на github репозиторий с проектом, где соберу весь код вместе.
Спасибо за прочтение.
Работа с видео
Для того, чтобы загрузить видео из галереи необходимо задать параметры(опции) запроса — PHVideoRequestOptions.
let options = PHVideoRequestOptions() // Указываем, что PHImageManager может загружать видео из iCloud options.isNetworkAccessAllowed = true // Выбираем автоматическое качество видео options.deliveryMode = .automatic options.progressHandler = { progress, _, _, _ in // Здесь можно отобразить текущий прогресс загрузки }
Далее эти параметры вместе с объектом PHAsset(см. предыдущую статью) передаем в следующую функцию:
PHImageManager.default().requestPlayerItem(forVideo: asset, options: options, resultHandler: { playerItem, info in // Можем использовать объект playerItem }
После того как получили playerItem, можно его воспроизвести. Для проигрывания видео используется класс AVPlayerLayer и AVPlayer:
let player = AVPlayer(playerItem: playerItem) let playerLayer = AVPlayerLayer(player: player) // Конфигурируем playerLayer и добавляем его во view player.play()
Работа с live-фото
Работа с live-фото и видео похожи. Для начала мы также задаем параметры запроса, только теперь с помощью класса PHLivePhotoRequestOptions:
let options = PHLivePhotoRequestOptions() options.isNetworkAccessAllowed = true options.deliveryMode = .highQualityFormat options.progressHandler = { progress, _, _, _ in // Здесь можно отобразить текущий прогресс загрузки }
Затем загружаем live-фото:
PHImageManager.default().requestLivePhoto(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: options, resultHandler: { livePhoto, info in // Можем использовать объект livePhoto })
После получения объекта livePhoto можем отобразить его в специальном компоненте PHLivePhotoView. Этот компонент очень похож на UIImageView. Он предназначен для отображения live-фото.
livePhotoView.livePhoto = livePhoto // Показываем live-фото livePhotoView.startPlayback(with: .full)
Отслеживание изменений в галерее
Photos framework позволяет следить за изменениями, произошедшими как с альбомами так и с отдельными фото или видео. Чтобы начать отслеживать изменения нужно добавить обсервер в PHPhotoLibrary:
PHPhotoLibrary.shared().register(observer)
Обсервер должен реализовывать протокол PHPhotoLibraryChangeObserver, в котором есть всего один метод — photoLibraryDidChange(_ changeInstance: PHChange). Параметр changeInstance — это объект, который содержит список изменений, произошедших в галерее.
В качестве примера покажу как обновить collectionView в соответствии с произошедшими изменениями.
func photoLibraryDidChange(_ changeInstance: PHChange) { // Получаем изменения списка PHAsset (переменная fetchResult) // Если изменений не было, то выходим из функции guard let changes = changeInstance.changeDetails(for: fetchResult) else { return } // Уведомление могло прийти не из main queue, поэтому перестраховываемся DispatchQueue.main.sync { // Присваиваем новый список PHAsset fetchResult = changes.fetchResultAfterChanges // Проверяем - можно ли получить список изменений по группам // (удалены, добавлены, изменены, перемещены) if changes.hasIncrementalChanges { // Анимируем изменения в collectionView collectionView.performBatchUpdates({ // Тут важно соблюсти порядок изменений: // delete, insert, reload, move if let removed = changes.removedIndexes where removed.count > 0 { collectionView.deleteItems(at: removed.map { IndexPath(item: $0, section:0) }) } if let inserted = changes.insertedIndexes where inserted.count > 0 { collectionView.insertItems(at: inserted.map { IndexPath(item: $0, section:0) }) } if let changed = changes.changedIndexes where changed.count > 0 { collectionView.reloadItems(at: changed.map { IndexPath(item: $0, section:0) }) } changes.enumerateMoves { fromIndex, toIndex in collectionView.moveItem(at: IndexPath(item: fromIndex, section: 0), to: IndexPath(item: toIndex, section: 0)) } }) } else { // Просто перезагружаем collectionView collectionView.reloadData() } } }
Заключение
Приведенный в статьях код не является идеальным. Главная его задача — показать механизм работы Photos framework. Если что-то было непонятно — спрашивайте в комментариях. Возможно, немного позже сделаю на github репозиторий с проектом, где соберу весь код вместе.
Спасибо за прочтение.
