Привет! В этой статье я расскажу про работу с видео, live-фото и отслеживание изменений в галерее с помощью Photos framework. Для лучшего понимания статьи рекомендую ознакомиться с предыдущей статьей.
Работа с видео
Для того, чтобы загрузить видео из галереи необходимо задать параметры(опции) запроса — 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 репозиторий с проектом, где соберу весь код вместе.
Спасибо за прочтение.
Автор: NoFearJoe