Вандад Нахавандипур - iOS. Приемы программирования
См. также
Разделы 17.12 и 17.14.
17.16. Анимирование и вращение видов
Постановка задачи
Требуется анимировать виды на экране при вращении.
Решение
Создайте аффинное преобразование вращения, для анимирования вращения пользуйтесь методами класса UIView.
Перед дальнейшей работой настоятельно рекомендую перечитать раздел 17.14.
Чтобы вращать вид, анимируя его при этом, нужно применить к нему преобразование вращения в то время, как в коде выполняется анимационный блок (см. раздел 17.12). Рассмотрим пример кода, который прояснит это. Допустим, у нас есть рисунок Xcode.png (см. рис. 17.9) и мы хотим отобразить его в центре экрана. После того как картинка появится на экране, мы повернем ее на 90° за 5 секунд, а потом повернем обратно, поставив в исходное положение. Итак, когда вид с изображением появится на экране, повернем этот вид на 90° по часовой стрелке:
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
self.xcodeImageView.center = self.view.center;
/* Начинаем анимацию. */
[UIView beginAnimations:@"clockwiseAnimation"
context: NULL];
/* Анимация будет длиться 5 секунд. */
[UIView setAnimationDuration:5.0f];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector:
@selector(clockwiseRotationStopped: finished: context:)];
/* Поворачиваем вид с изображением на 90°. */
self.xcodeImageView.transform =
CGAffineTransformMakeRotation((90.0f * M_PI) / 180.0f);
/* Выполняем анимацию. */
[UIView commitAnimations];
}
Мы решили, что селектор clockwiseRotationStopped: finished: context: должен вызываться в тот момент, когда заканчивается анимация вращения по часовой стрелке. В этом методе мы будем вращать вид с изображением против часовой стрелки, обратно в положение, соответствующее 0° (то есть исходное). На это тоже уйдет 5 секунд.
— (void)clockwiseRotationStopped:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
[UIView beginAnimations:@"counterclockwiseAnimation"
context: NULL];
/* 5 секунд */
[UIView setAnimationDuration:5.0f];
/* Возврат в исходное положение */
self.xcodeImageView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
Как было показано в разделах 17.14 и 17.15, а также в этом разделе, существует много способов анимировать виды (прямые или непрямые подклассы UIView). При выполнении анимации можно изменять немало свойств. Будьте креативны и экспериментируйте с другими свойствами UIView, о которых раньше, возможно, не знали. Не помешает также еще раз пересмотреть документацию по UIView в органайзере Xcode.
См. также
Разделы 17.13–17.15.
17.17. Получение изображения со скриншотом вида
Постановка задачи
Требуется сохранить содержимое объекта-вида, находящегося в вашем приложении, в виде изображения. Возможно, также потребуется сохранить это изображение на диске и выполнить с ним другое действие — например, позволить пользователю поделиться этой картинкой в любимой социальной сети (см. раздел 11.11).
Решение
Выполните следующие шаги.
1. Воспользуйтесь функцией UIGraphicsBeginImageContextWithOptions для создания нового контекста изображения. Этот контекст сразу станет текущим (актуальным), и именно в нем будет происходить все последующее рисование.
2. Вызовите метод drawViewHierarchyInRect: вашего класса UIView. В качестве параметра передайте этому методу границы вида, который вы хотите отрисовать в текущем контексте.
3. Вызовите метод UIGraphicsGetImageFromCurrentImageContext, возвращаемое значение которого — это представление текущего контекста в качестве изображения. Это изображение будет относиться к типу UIImage.
4. Преобразуйте ваш экземпляр изображения в данные, воспользовавшись функцией UIImagePNGRepresentation. Эта функция даст вам объект типа NSData.
5. Наконец, вызовите в вашем объекте данных метод экземпляра writeToUrl: atomically:, чтобы записать изображение на определенный адрес на диске — если хотите. Имея экземпляр UIImage, можете выполнить с этим изображением и любую другую операцию.
Обсуждение
Иногда разработчику требуется программно делать скриншот содержимого, которое отображается на экране устройства. В частности, это может понадобиться, если вы пишете приложение для рисования и хотите предоставить пользователю возможность сохранить сделанный рисунок в файле. Возможно, этот файл затем будет сохранен в облаке iCloud, откуда его можно будет впоследствии загрузить.
Перед тем как сохранить изображение или поделиться им таким образом, мы должны нарисовать его в контексте изображения. Контекст изображения остается для нас невидимым, так как мы даже не имеем его описателя. Тем не менее все рисовальные методы, которые вы вызываете, будут оказывать влияние на текущий контекст изображения. Контекст изображения можно сравнить с невидимым холстом для рисования. Чтобы получить представление вашего изображения, воспользуйтесь функцией UIGraphicsGetImageFromCurrentImageContext.
Когда вы начнете решать такую задачу с помощью нового SDK, вам всего лишь потребуется вызвать в виде метод drawViewHierarchyInRect: — и содержимое этого вида будет отрисовано в текущем контексте.
Итак, применим изученный материал на практике. В следующем фрагменте кода мы собираемся разместить в нашем виде ряд компонентов (при этом используются раскадровки, описанные в главе 6). Не важно, что именно вы поместите в раскадровке. Мы хотим снять содержимое нашего вида, сохранить эту информацию как изображение, а затем поместить это изображение в каталог Documents (Документы) на диске:
— (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
/* Делаем скриншот */
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0f);
if ([self.view drawViewHierarchyInRect: self.view.bounds]){
NSLog(@"Successfully draw the screenshot.");
} else {
NSLog(@"Failed to draw the screenshot.");
}
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Сохраняем его на диске */
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *documentsFolder = [fileManager URLForDirectory: NSDocumentDirectory
inDomain: NSUserDomainMask
appropriateForURL: nil
create: YES
error: nil];
NSURL *screenshotUrl = [documentsFolder
URLByAppendingPathComponent:@"screenshot.png"];
NSData *screenshotData = UIImagePNGRepresentation(screenshot);
if ([screenshotData writeToURL: screenshotUrl atomically: YES]){
NSLog(@"Successfully saved screenshot to %@", screenshotUrl);
} else {
NSLog(@"Failed to save screenshot.");
}
}
В начале этого кода мы создаем новый контекст изображения и получаем его представление в виде изображения с помощью UIGraphicsGetImageFromCurrentImageContext. Имея это представление, мы воспользуемся NSFileManager, чтобы найти путь к каталогу Documents (Документы) нашего приложения, который находится на диске (см. раздел 12.1). Наконец, мы получаем представление скриншота в виде данных (с помощью функции UIImagePNGRepresentation) и после этого можем сохранить данное представление на диске. Мы должны получить представление изображения в формате PNG или JPEG, воспользовавшись для этого функцией UIImageJPEGRepresentation. Так мы получим данные, соответствующие изображению в этом формате (PNG/JPEG). Имея данные, мы можем сохранить их на диске или выполнить с ними другие операции.
См. также
Раздел 11.11, глава 6.
Глава 18. Фреймворк Core Motion
18.0. Введение
Устройства с операционной системой iOS, в частности iPhone и iPad, обычно оборудованы акселерометром. На некоторых устройствах, например новых iPhone и iPad, есть также гироскоп. Прежде чем пытаться использовать в ваших приложениях для iOS акселерометр или гироскоп, нужно проверить доступность (наличие) этих сенсоров на том устройстве, на котором работает ваша программа. В разделах 18.1 и 18.2 описаны приемы, которые можно использовать для обнаружения акселерометра или гироскопа. Устройства iOS, оснащенные гироскопом, могут регистрировать движение вдоль шести осей.
Рассмотрим ситуацию, которая позволяет оценить, насколько полезен гироскоп. Например, акселерометр не может обнаружить вращение устройства вокруг его вертикальной оси, если вы крепко держите устройство в руках, сидите в компьютерном кресле и крутитесь на нем по часовой стрелке или против часовой стрелки. Относительно пола в вашей комнате или относительно планеты Земля устройство вращается вокруг вертикальной оси, но оно при этом не вращается вокруг собственной оси Y, проходящей по вертикали через центр устройства, то есть акселерометр не обнаружит никакого движения.