Текст книги "iOS. Приемы программирования"
Автор книги: Вандад Нахавандипур
Жанр: Зарубежная компьютерная литература, Зарубежная литература
сообщить о неприемлемом содержимом
Текущая страница: 43 (всего у книги 59 страниц)
Фреймворк Assets Library – удобный посредник между разработчиком и библиотекой фотографий. Как будет указано в разделе 13.6, в iOS SDK вам предоставляются встроенные компоненты графического пользовательского интерфейса, которыми можно пользоваться для доступа к содержимому библиотеки фотографий. Тем не менее иногда может потребоваться и непосредственный доступ к этому содержимому. В таких случаях следует пользоваться фреймворком библиотеки ресурсов (Assets Library).
Выделив и инициализировав объект Assets Library типа ALAssetsLibrary, можно пользоваться методом экземпляра writeVideoAtPathToSavedPhotosAlbum: completionBlock:, относящимся к данному объекту, для записи видео с URL в библиотеку фотографий. Все, что от вас требуется, – предоставить URL видеоролика в форме NSURL, а также блоковый объект, чей код будет вызываться после сохранения видео. Этот блоковый объект должен принимать два параметра типов NSURL и NSError.
Если параметр error имеет значение nil, процесс сохранения прошел нормально и поводов для беспокойства нет. Одна из типичных ошибок, которую iOS может вам вернуть в такой ситуации, примерно такова:
Error Domain=ALAssetsLibraryErrorDomain Code=-3302 «Invalid data»
UserInfo=0x79 23590 {NSLocalizedFailureReason=
There was a problem writing this asset because
the data is invalid and cannot be viewed or played.,
NSLocalizedRecoverySuggestion=Try with different data,
NSLocalizedDescription=Invalid data}
Такое сообщение об ошибке вы можете получить и в случае, если попытаетесь передать URL (уникальный идентификатор ресурса), не относящийся к пакету вашего приложения.
Первый параметр, передаваемый блоковому объекту, который, в свою очередь, предоставляется методу writeVideoAtPathToSavedPhotosAlbum: completionBlock:, будет указывать URL видео, сохраненного в библиотеке ресурсов. URL такого рода может иметь следующий вид:
assets-library://asset/asset.MOV?id=F9B5F733-487C-
4418-8C8D-46ABC9FEE23B&ext=MOV
Если ваша программа впервые пытается обратиться к библиотеке фотографий на пользовательском устройстве, то iOS спросит у пользователя, разрешена такая операция или нет. Если пользователь даст разрешение, то вызов метода writeVideoAtPathToSavedPhotosAlbum: completionBlock: будет успешным. Если же разрешение получено не будет, то объект ошибки внутри блока завершения будет валидным объектом ошибки, который вы можете проверить и над которым можете выполнять действия. Если ранее пользователь не разрешил вашему приложению доступ к библиотеке фотографий, то вы не сможете изменить это решение программно. Лишь когда сам пользователь решит предоставить вам доступ к библиотеке фотографий, он изменит соответствующие настройки в разделах Settings (Настройки) и Privacy (Конфиденциальность).
В разделе 13.7 будет рассказано, как использовать такой URL при загрузке в память данных для видеофайла.
13.6. Получение фото и видео из библиотеки фотографий
Постановка задачиНеобходимо предоставить пользователю возможность выбирать фото или видео из своей библиотеки фотографий и использовать их в приложении.
РешениеПри работе с объектом UIImagePickerController используйте UIImagePickerControllerSourceTypePhotoLibrary в качестве типа источника и значение kUTTypeImage или kUTTypeMovie для типа медийной информации:
– (BOOL) isPhotoLibraryAvailable{
return [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary];
}
– (BOOL) canUserPickVideosFromPhotoLibrary{
return [self
cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType: UIImagePickerControllerSourceTypePhotoLibrary];
}
– (BOOL) canUserPickPhotosFromPhotoLibrary{
return [self
cameraSupportsMedia:(__bridge NSString *)kUTTypeImage
sourceType: UIImagePickerControllerSourceTypePhotoLibrary];
}
– (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
}
if ([self isPhotoLibraryAvailable]){
UIImagePickerController *controller =
[[UIImagePickerController alloc] init];
controller.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
NSMutableArray *mediaTypes = [[NSMutableArray alloc] init];
if ([self canUserPickPhotosFromPhotoLibrary]){
[mediaTypes addObject:(__bridge NSString *)kUTTypeImage];
}
if ([self canUserPickVideosFromPhotoLibrary]){
[mediaTypes addObject:(__bridge NSString *)kUTTypeMovie];
}
controller.mediaTypes = mediaTypes;
controller.delegate = self;
[self.navigationController presentModalViewController: controller
animated: YES];
}
}
О том, как реализовать метод cameraSupportsMedia: sourceType:, который используется в этом примере, рассказано в разделе 13.1.
ОбсуждениеЧтобы пользователь мог выбирать фотоснимки или видеоролики из своей библиотеки фотографий, необходимо установить свойство sourceType экземпляра UIImagePickerController в значение UIImagePickerControllerSourceTypePhotoLibrary и только потом открывать перед пользователем инструмент для выбора изображений. Кроме того, если вы хотите отфильтровать определенные фотографии или видеоролики из общего числа элементов, представленных пользователю в инструменте для выбора изображений, исключите значение kUTTypeMovie или kUTTypeImage соответственно из списка типов медийной информации, отображаемой в инструменте для выбора изображений (это делается в свойстве mediaTypes).
Учитывайте, что, если установить значение свойства mediaTypes контроллера для выбора изображений в nil, получится пустой массив, который спровоцирует ошибки времени исполнения.
После того как пользователь выберет желаемое изображение, вы будете получать обычные сообщения делегата, соответствующие протоколу UIImagePickerControllerDelegate. Подробнее о реализации методов, определяемых в этом протоколе для обработки изображений, рассказано в разделе 13.2.
См. такжеРаздел 13.7.
13.7. Получение ресурсов из библиотеки ресурсов
Постановка задачиТребуется получить фотографии или видео непосредственно из библиотеки фотографий, не прибегая к использованию каких-либо встроенных компонентов графического пользовательского интерфейса.
РешениеВоспользуйтесь фреймворком Assets Library (Библиотека ресурсов). Выполните следующие шаги.
1. Выделите и инициализируйте объект типа ALAssetsLibrary.
2. Передайте два блоковых объекта методу экземпляра enumerateGroupsWithTypes: usingBlock: failureBlock:, относящемуся к объекту «Библиотека ресурсов». Первый блок получит все группы, ассоциированные с типом, который мы сообщили этому методу. Группы будут относиться к типу ALAssetsGroup. В случае неудачи этой операции во втором блоке будет возвращена ошибка.
3. Воспользуйтесь методом экземпляра enumerateAssetsUsingBlock: каждого группового объекта для перечисления ресурсов, имеющихся в каждой группе. Этот метод принимает единственный параметр – блок, получающий информацию по отдельно взятому ресурсу. Блок, передаваемый в качестве параметра, должен принимать три параметра, первый из которых должен относиться к типу ALAsset.
4. Получив объекты ALAsset, доступные в каждой группе, вы можете затем найти различные свойства каждого ресурса: его тип, доступные URL и т. д. Для получения этих свойств примените метод экземпляра valueForProperty:, относящийся к каждому ресурсу типа ALAsset. Возвращаемое значение этого метода в зависимости от типа передаваемого ему параметра может представлять собой NSDictionary, NSString или любой другой тип объекта. Вскоре мы рассмотрим общие свойства, которые могут быть получены от любого ресурса.
5. Вызовите метод экземпляра defaultRepresentation каждого объекта типа ALAsset, чтобы получить его объект представления (Representation Object) типа ALAssetRepresentation. Каждый ресурс из библиотеки ресурсов может иметь более одного представления. Например, фотография по умолчанию может иметь представление в формате PNG, но, кроме того, обладать и представлением JPEG. С помощью метода defaultRepresentation каждого ресурса типа ALAsset можно получить объект ALAssetRepresentation, а потом использовать его для получения различных представлений каждого ресурса (при наличии таких представлений).
6. Пользуйтесь методами size и методами экземпляра getBytes: fromOffset: length: error: каждого представления ресурса для загрузки данных о представлении ресурса. Затем можно записать прочитанные байты в объект NSData или выполнить любую другую операцию, необходимую в ходе работы приложения. Кроме того, при работе с фотографиями можно использовать методы экземпляра fullResolutionImage, fullScreenImage и CGImageWithOptions: каждого представления, чтобы получать изображения типа CGImageRef. Потом можно создать UIImage из CGImageRef с помощью метода класса imageWithCGImage:, относящегося к классу UIImage:
– (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
}
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
[self.assetsLibrary
enumerateGroupsWithTypes: ALAssetsGroupAll
usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock: ^(ALAsset *result,
NSUInteger index,
BOOL *stop) {
/* Получаем тип ресурса. */
NSString *assetType = [result valueForProperty: ALAssetPropertyType];
if ([assetType isEqualToString: ALAssetTypePhoto]){
NSLog(@"This is a photo asset");
}
else if ([assetType isEqualToString: ALAssetTypeVideo]){
NSLog(@"This is a video asset");
}
else if ([assetType isEqualToString: ALAssetTypeUnknown]){
NSLog(@"This is an unknown asset");
}
/* Получаем все URL для ресурса. */
NSDictionary *assetURLs =
[result valueForProperty: ALAssetPropertyURLs];
NSUInteger assetCounter = 0;
for (NSString *assetURLKey in assetURLs){
assetCounter++;
NSLog(@"Asset URL %lu = %@",
(unsigned long)assetCounter,
[assetURLs valueForKey: assetURLKey]);
}
/* Получаем объект представления ресурса. */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];
NSLog(@"Representation Size = %lld", [assetRepresentation size]);
}];
}
failureBlock: ^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];
}
Библиотека ресурсов подразделяется на группы. В каждой группе содержатся ресурсы, а каждый ресурс имеет свойства, например URL (универсальные локаторы ресурсов) и объекты представления.
Все ресурсы всех типов можно получать из библиотеки ресурсов с помощью константы ALAssetsGroupAll. Она передается параметру enumerateGroupsWithTypes метода экземпляра enumerateGroupsWithTypes: usingBlock: failureBlock:, относящегося к объекту «Библиотека ресурсов». Вот список значений, которые можно передать этому параметру для перечисления различных групп ресурсов:
• ALAssetsGroupAlbum – группы, содержащие альбомы, которые были сохранены на устройстве iOS из iTunes;
• ALAssetsGroupFaces – группы, содержащие альбомы, в которых представлены фотографии лиц, сохраненные на устройстве iOS из iTunes;
• ALAssetsGroupSavedPhotos – группы, содержащие снимки, которые сохранены в библиотеке фотографий. На устройстве iOS эти ресурсы доступны также через приложение Photos (Фотографии);
• ALAssetsGroupAll – все группы, доступные в библиотеке ресурсов.
Теперь напишем простое приложение, которое будет получать данные о первом изображении, найденном в библиотеке ресурсов, создавать UIImageView с этим изображением, а потом добавлять это изображение в вид того контроллера вида, который отображается в настоящий момент. На данном примере мы научимся считывать содержимое ресурса, используя его представление.
Когда контроллер вида отображает свой вид, мы инициализируем объект библиотеки ресурсов и начнем перечисление ресурсов в этой библиотеке, пока не найдем первую фотографию. На данном этапе будем использовать представление этого ресурса (фотографии), чтобы отобразить фотографию в виде с изображением:
– (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
}
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(dispatchQueue, ^(void) {
[self.assetsLibrary
enumerateGroupsWithTypes: ALAssetsGroupAll
usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock: ^(ALAsset *result,
NSUInteger index,
BOOL *stop) {
__block BOOL foundThePhoto = NO;
if (foundThePhoto){
*stop = YES;
}
/* Получаем тип ресурса. */
NSString *assetType = [result
valueForProperty: ALAssetPropertyType];
if ([assetType isEqualToString: ALAssetTypePhoto]){
NSLog(@"This is a photo asset");
foundThePhoto = YES;
*stop = YES;
/* Получаем объект представления ресурса. */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];
/* Нам требуются данные о масштабе и ориентации, чтобы можно
было создать правильно расположенное и вымеренное изображение
UIImage из нашего объекта представления. */
CGFloat imageScale = [assetRepresentation scale];
UIImageOrientation imageOrientation =
(UIImageOrientation)[assetRepresentation orientation];
dispatch_async(dispatch_get_main_queue(), ^(void) {
CGImageRef imageReference =
[assetRepresentation fullResolutionImage];
/* Сейчас создаем изображение. */
UIImage *image =
[[UIImage alloc] initWithCGImage: imageReference
scale: imageScale
orientation: imageOrientation];
if (image!= nil){
self.imageView = [[UIImageView alloc]
initWithFrame: self.view.bounds];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = image;
[self.view addSubview: self.imageView];
} else {
NSLog(@"Failed to create the image.");
}
});
}
}];
}
failureBlock: ^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];
});
}
Мы перечисляем группы и каждый ресурс в группе. Потом находим первый ресурс-фотографию и получаем его представление. С помощью этого представления создаем UIImage, а уже из UIImage делаем UIImageView для демонстрации изображения в виде. Ничего сложного, правда?
Работа с видеофайлами строится немного иначе, поскольку в классе ALAssetRepresentation нет каких-либо методов, способных возвращать объект, заключающий в себе видеофайл. Поэтому нам потребуется считать содержимое видеоресурса в буфер и, возможно, сохранить его в каталоге Documents, где впоследствии к этому документу будет проще получить доступ. Разумеется, конкретные требования зависят от определенного приложения, но в приведенном далее примере кода мы пойдем дальше – найдем первый видеофайл в библиотеке ресурсов и сохраним его в каталоге Documents в приложении под названием Temp.MOV:
– (NSString *) documentFolderPath{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *url = [fileManager URLForDirectory: NSDocumentDirectory
inDomain: NSUserDomainMask
appropriateForURL: nil
create: NO
error: nil]
return url.path;
}
– (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
}
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(dispatchQueue, ^(void) {
[self.assetsLibrary
enumerateGroupsWithTypes: ALAssetsGroupAll
usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
__block BOOL foundTheVideo = NO;
[group enumerateAssetsUsingBlock: ^(ALAsset *result,
NSUInteger index,
BOOL *stop) {
/* Получаем тип ресурса. */
NSString *assetType = [result
valueForProperty: ALAssetPropertyType];
if ([assetType isEqualToString: ALAssetTypeVideo]){
NSLog(@"This is a video asset");
foundTheVideo = YES;
*stop = YES;
/* Получаем объект представления ресурса. */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];
const NSUInteger BufferSize = 1024;
uint8_t buffer[BufferSize];
NSUInteger bytesRead = 0;
long long currentOffset = 0;
NSError *readingError = nil;
/* Создаем путь, по которому должно быть сохранено видео. */
NSString *videoPath = [documentsFolder
stringByAppendingPathComponent:@"Temp.MOV"];
NSFileManager *fileManager = [[NSFileManager alloc] init];
/* Создаем файл, если он еще не существует. */
if ([fileManager fileExistsAtPath: videoPath] == NO){
[fileManager createFileAtPath: videoPath
contents: nil
attributes: nil];
}
/* Этот дескриптор файла мы будем использовать для записи
медийных ресурсов на диск. */
NSFileHandle *fileHandle = [NSFileHandle
fileHandleForWritingAtPath: videoPath];
do{
/* Считываем столько байтов, сколько можем поместить в буфер. */
bytesRead = [assetRepresentation getBytes:(uint8_t *)&buffer
fromOffset: currentOffset
length: BufferSize
error:&readingError];
/* Если ничего считать не можем, то выходим из этого цикла. */
if (bytesRead == 0){
break;
}
/* Данные о смещении буфера должны быть актуальными. */
currentOffset += bytesRead;
/* Помещаем буфер в объект NSData. */
NSData *readData = [[NSData alloc]
initWithBytes:(const void *)buffer
length: bytesRead];
/* И записываем данные в файл. */
[fileHandle writeData: readData];
} while (bytesRead > 0);
NSLog(@"Finished reading and storing the
video in the documents folder");
}
}];
if (foundTheVideo){
*stop = YES;
}
}
failureBlock: ^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];
});
}
Вот что происходит в данном коде.
1. Мы получаем стандартное представление первого видеоресурса, который находим в библиотеке ресурсов.
2. Создаем файл Temp.MOV в каталоге Documents нашего приложения для сохранения содержимого видеоресурса.
3. Создаем цикл, работающий до тех пор, пока в представлении ресурса еще остаются данные, которые необходимо считать. Метод экземпляра getBytes: fromOffset: length: error:, относящийся к объекту представления ресурса, считывает столько байтов, сколько может поместиться в буфер, и проделывает это столько раз, сколько необходимо, пока мы не достигнем конца данных представления.
4. После считывания данных в буфер мы заключаем их в объект типа NSData, используя для этого метод инициализации initWithBytes: length: класса NSData. Затем записываем эти данные в файл, созданный ранее, с помощью метода экземпляра writeData:, относящегося к классу NSFileHandle.
13.8. Редактирование видео на устройстве с операционной системой iOS
Постановка задачиТребуется, чтобы пользователь, просматривающий видео, мог редактировать видео в этом же приложении.
РешениеВоспользуйтесь классом UIVideoEditorController. В приведенном здесь примере используем данный класс вместе с контроллером для выбора изображений. Сначала мы предлагаем пользователю выбрать снимок из его библиотеки фотографий. После того как выбор будет сделан, отображаем экземпляр контроллера видеоредактора, где пользователь может обрабатывать выбранное видео.
ОбсуждениеКласс UIVideoEditorController, содержащийся в iOS SDK, позволяет программисту вывести на экран перед пользователем специальный интерфейс для редактирования. Все, что требуется сделать, – предоставить URL видеоролика, который предполагается отредактировать, а потом отобразить в модальном виде контроллер для редактирования видео. Не допускайте наложения вида этого контроллера на любые другие виды и не изменяйте этот вид.
При вызове метода presentModalViewController: animated: сразу же после метода dismissModalViewControllerAnimated: контроллера вида приложение завершится с ошибкой времени исполнения. Необходимо дождаться, пока первый контроллер вида не будет убран с экрана, и только потом отображать второй контроллер вида. Можно пользоваться относящимся к контроллерам вида методом viewDidAppear:, помогающим определить, когда отобразится ваш вид. На данном этапе можно быть уверенным, что все модальные контроллеры видов уже убраны.
Итак, продолжим и объявим контроллер вида со всеми необходимыми свойствами:
#import «ViewController.h»
#import <MobileCoreServices/MobileCoreServices.h>
#import <AssetsLibrary/AssetsLibrary.h>
@interface ViewController ()
<UINavigationControllerDelegate,
UIVideoEditorControllerDelegate,
UIImagePickerControllerDelegate>
@property (nonatomic, strong) NSURL *videoURLToEdit;
@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;
@end
@implementation ViewController
<# Остаток вашего кода находится здесь #>
Далее нужно обработать различные сообщения, получаемые от делегата видеоредактора в контроллере вида:
– (void)videoEditorController:(UIVideoEditorController *)editor
didSaveEditedVideoToPath:(NSString *)editedVideoPath{
NSLog(@"The video editor finished saving video");
NSLog(@"The edited video path is at = %@", editedVideoPath);
[editor dismissModalViewControllerAnimated: YES];
}
– (void)videoEditorController:(UIVideoEditorController *)editor
didFailWithError:(NSError *)error{
NSLog(@"Video editor error occurred = %@", error);
[editor dismissModalViewControllerAnimated: YES];
}
– (void)videoEditorControllerDidCancel:(UIVideoEditorController *)editor{
NSLog(@"The video editor was cancelled");
[editor dismissModalViewControllerAnimated: YES];
}
Когда вид загрузится, мы должны будем отобразить для пользователя вид для выбора видео. Видео он может выбрать из библиотеки, а потом мы предоставим возможность его обрабатывать:
– (BOOL) cameraSupportsMedia:(NSString *)paramMediaType
sourceType:(UIImagePickerControllerSourceType)paramSourceType{
__block BOOL result = NO;
if ([paramMediaType length] == 0){
NSLog(@"Media type is empty.");
return NO;
}
NSArray *availableMediaTypes =
[UIImagePickerController
availableMediaTypesForSourceType: paramSourceType];
[availableMediaTypes enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {
NSString *mediaType = (NSString *)obj;
if ([mediaType isEqualToString: paramMediaType]){
result = YES;
*stop= YES;
}
}];
return result;
}
– (BOOL) canUserPickVideosFromPhotoLibrary{
return [self cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType: UIImagePickerControllerSourceTypePhotoLibrary];
}
– (BOOL) isPhotoLibraryAvailable{
return [UIImagePickerController
isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary];
}
– (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
}
if ([self isPhotoLibraryAvailable] &&
[self canUserPickVideosFromPhotoLibrary]){
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc] init];
/* Задаем тип источника для библиотеки фотографий. */
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
/* Требуется, чтобы пользователь мог выбирать видеоролики
из библиотеки. */
NSArray *mediaTypes = [[NSArray alloc] initWithObjects:
(__bridge NSString *)kUTTypeMovie, nil];
imagePicker.mediaTypes = mediaTypes;
/* Задаем делегат для текущего контроллера вида. */
imagePicker.delegate = self;
/* Отображаем окно для выбора изображений. */
[self.navigationController presentModalViewController: imagePicker
animated: YES];
}
}
Далее нам необходимо узнать, когда пользователь сделает выбор (то есть выберет видеоролик). Обработаем различные сообщения делегата, обслуживающего инструмент для выбора изображений:
– (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSLog(@"Picker returned successfully.");
NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]){
self.videoURLToEdit =
[info objectForKey: UIImagePickerControllerMediaURL];
}
[picker dismissModalViewControllerAnimated: YES];
/* Сначала убедимся, что редактор видео способен обрабатывать видео,
путь к которому в папке документов мы указали. */
if ([UIVideoEditorController canEditVideoAtPath: videoPath]){
/* Инстанцируем редактор видео. */
UIVideoEditorController *videoEditor =
[[UIVideoEditorController alloc] init];
/* Становимся делегатом видеоредактора. */
videoEditor.delegate = self;
/* Убеждаемся, что задали путь к видеоролику. */
videoEditor.videoPath = videoPath;
/* А теперь отображаем видеоредактор. */
[self.navigationController presentModalViewController: videoEditor
animated: YES];
self.videoURLToEdit = nil;
} else {
NSLog(@"Cannot edit the video at this path");
}
}
}];
}
– (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker{
NSLog(@"Picker was cancelled");
self.videoURLToEdit = nil;
[picker dismissViewControllerAnimated: YES completion: nil];
}
В данном примере пользователь может выбрать любое видео из библиотеки фотографий. Как только он это сделает, мы отобразим контроллер видеоредактора, указав путь к видеоролику. Этот путь передает нам инструмент для выбора видео в методе делегата.
Делегат контроллера видеоредактора получает важные сообщения о состоянии этого видеоредактора. Объект делегата должен соответствовать протоколам UIVideoEditorControllerDelegate и UINavigationControllerDelegate. В данном примере мы решили, что делегатом видеоредактора должен стать контроллер вида. Как только редактирование будет закончено, объект делегата получит от контроллера видеоредактора метод делегата videoEditorController: didSaveEditedVideoToPath:. Путь к отредактированному видео будет передан в параметре didSaveEditedVideoToPath.
Прежде чем попытаться отобразить для пользователя интерфейс видеоредактора, нужно вызывать метод класса canEditVideoAtPath:, относящийся к классу UIVideoEditorController. Мы это делаем, чтобы убедиться, что тот путь, который вы пытаетесь редактировать, доступен для обработки в контроллере. Если возвращаемое значение этого метода класса равно YES, можно переходить к конфигурированию и отображению интерфейса редактора видео. Если нет – идем другим путем. Возможно, потребуется отобразить для пользователя предупреждение.
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.