iOS: Работа с галереей (Photos framework). Часть 2

Привет, Хабр! В этой статье я расскажу про работу с видео, 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 репозиторий с проектом, где соберу весь код вместе.
Спасибо за прочтение.

Комментарии (0)

© Habrahabr.ru