Вандад Нахавандипур - iOS. Приемы программирования
Разделы 17.11 и 17.12.
17.14. Анимирование и перемещение видов
Постановка задачи
Требуется анимировать смещение видов.
Решение
При смещении видов используйте анимационные методы класса UIView.
Обсуждение
В операционной системе iOS предоставляются различные способы выполнения анимации, среди этих возможностей есть как низкоуровневые, так и сравнительно высокоуровневые. Самый высокий уровень работы в данном случае обеспечивается во фреймворке UIKit, о котором мы также поговорим в этом разделе. В UIKit содержится некоторая низкоуровневая функциональность Core Animation, предоставляемая нам в форме довольно аккуратного API, с которым очень удобно работать.
Работа с анимацией в UIKit начинается с вызова метода класса beginAnimations: context:, относящегося к классу UIView. Первый параметр — это опциональное имя, которое вы можете выбрать для вашей анимации, а второй — опциональный контекст, который можно получить позже для передачи анимационным методам делегатов. Вскоре мы поговорим о них обоих.
После того как вы запустите анимацию с помощью метода beginAnimations: context:, она не начнет происходить, так как для этого потребуется еще вызвать метод класса commitAnimations, относящийся к классу UIView. Вычисления, которые вы производите над объектом-видом между вызовом beginAnimations: context: и commitAnimations (в результате которых этот вид, к примеру, перемещается), будут сопровождаться анимацией только после вызова commitAnimations. Рассмотрим пример.
Как упоминалось в разделе 17.4, я включил в пакет моего приложения рисунок Xcode.png. Это ярлык Xcode, который я нашел в картинках Google (см. рис. 17.9). Теперь в моем контроллере вида (см. введение к этой главе) я хочу поместить этот рисунок в виде с изображением типа UIImageView, а потом переместить этот вид с изображением из верхнего левого угла экрана в нижний правый угол.
Вот как мы решим эту задачу.
1. Откройте. h-файл вашего контроллера вида.
2. Определите экземпляр UIImageView как свойство контроллера вида и назовите его xcodeImageView:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UIImageView *xcodeImageView;
@end
3. Когда вид загрузится, поместите изображение Xcode.png в экземпляр UIImage:
— (void) viewDidLoad{
[super viewDidLoad];
UIImage *xcodeImage = [UIImage imageNamed:@"Xcode.png"];
self.xcodeImageView = [[UIImageView alloc]
initWithImage: xcodeImage];
/* Просто задаем размеры, чтобы изображение уменьшилось. */
[self.xcodeImageView setFrame: CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview: self.xcodeImageView];
}
4. На рис. 17.33 показано, как будет выглядеть вид, когда программа запускается в симуляторе iOS.
Рис. 17.33. Добавление вида с изображением в объект-вид
5. Теперь, когда вид появится на экране в методе экземпляра viewDidAppear: контроллера вида, приступим к исполнению анимационного блока, относящегося к виду с изображением. Эта анимация переместит изображение из исходной точки (в левом верхнем углу) в нижний правый угол. Кроме того, мы убедимся, что анимация произойдет за пятисекундный период:
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
/* Начинаем с верхнего левого угла. */
[self.xcodeImageView setFrame: CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[UIView beginAnimations:@"xcodeImageViewAnimation"
context:(__bridge void *)self.xcodeImageView];
/* Пятисекундная анимация. */
[UIView setAnimationDuration:5.0f];
/* Получаем делегаты анимации. */
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop: finished: context:)];
/* Анимация заканчивается в нижнем правом углу. */
[self.xcodeImageView setFrame: CGRectMake(200.0f,
350.0f,
100.0f,
100.0f)];
[UIView commitAnimations];
}
6. Далее выполните реализацию метода делегата imageViewDidStop: finished: context: для контроллера вида, чтобы он вызывался UIKit по завершении анимации. Это не обязательно, так что для примера я просто зарегистрирую несколько сообщений, демонстрирующих, что метод действительно был вызван. В следующих примерах будет показано, как можно использовать метод для запуска какой-то иной активности в момент окончания анимации:
— (void)imageViewDidStop:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
NSLog(@"Animation finished.");
NSLog(@"Animation ID = %@", paramAnimationID);
UIImageView *contextImageView = (__bridge UIImageView *)paramContext;
NSLog(@"Image View = %@", contextImageView);
}
Теперь, запустив приложение, вы заметите, что, как только отобразится вид, изображение, показанное на рис. 17.33, начнет перемещаться в нижний правый угол (рис. 17.34). На это уйдет 5 секунд.
Рис. 17.34. Анимируемое изображение переходит в правый нижний угол экрана
Кроме того, обратив внимание на консоль и дождавшись окончания анимации, вы увидите примерно следующий текст:
Animation finished.
Animation ID = xcodeImageViewAnimation
Image View = <UIImageView: 0x8eaee20;
frame = (220 468; 100 100); opaque = NO;
userInteractionEnabled = NO;
layer = <CALayer: 0x8eaef10>>
А теперь рассмотрим конкретные концепции и разберемся, как именно мы анимировали этот вид с изображением. Далее перечислены важные методы класса, относящиеся к UIView, о которых нужно знать, занимаясь анимацией с UIKit.
• beginAnimations: context: — запускает анимационный блок. Любое анимируемое изменение свойств, которое вы применяете к видам после вызова этого метода класса, будет вступать в силу после выполнения анимации.
• setAnimationDuration: — этот метод задает длительность анимации в секундах.
• setAnimationDelegate: — задает объект, который будет получать сообщения делегатов, касающиеся различных событий, которые могли произойти до, во время или после анимации. Если мы задаем объект делегата, это не означает, что анимационные делегаты немедленно запускаются. Кроме того, вы должны использовать различные методы-установщики, относящиеся к классу, применяя их к объекту вида. Так вы сообщаете UIKit, какие селекторы в вашем объекте-делегате какие делегатные сообщения должны получать.
• setAnimationDidStopSelector: — задает в объекте-делегате метод, который должен быть вызван после завершения анимации. Этот метод должен принимать три параметра в следующем порядке:
1) идентификатор анимации типа NSString: здесь будет содержаться идентификатор анимации, передаваемый с началом анимации методу класса beginAnimations: context:, относящемуся к классу UIView;
2) индикатор «завершения» типа NSNumber: этот параметр содержит в NSNumber логическое значение. Среда времени исполнения устанавливает его в YES, если анимация была остановлена в коде, не успев полностью завершиться. Если это значение равно NO, то это означает, что анимация была без перерывов воспроизведена до самого конца;
3) контекст типа void *: это контекст, который с началом анимации передается методу класса beginAnimations: context:, относящемуся к классу UIView.
• setAnimationWillStartSelector: — задает селектор, который должен быть вызван в объекте делегата перед самым началом анимации. Селектор, передаваемый этому методу класса, должен иметь два параметра в таком порядке:
1) идентификатор анимации типа NSString: среда времени исполнения задает для этого параметра значение идентификатора анимации, передаваемого с началом анимации методу класса beginAnimations: context:, относящемуся к классу UIView;
2) контекст типа void *: это контекст, который с началом анимации был передан методу класса beginAnimations: context:, относящемуся к классу UIView.
• setAnimationDelay: — задает задержку для анимации (в секундах) перед ее началом. Например, если это значение установлено в 3.0f, то анимация будет начинаться через 3 секунды после выполнения этого метода.
• setAnimationRepeatCount: — указывает количество прогонов анимации, которые должны быть выполнены в блоке кода.
Теперь, когда нам известны наиболее полезные методы класса UIView, помогающие анимировать виды, рассмотрим другую анимацию. В этом примере кода я создам два вида с изображениями (в каждом из них будет показано одно и то же изображение), и они появятся на экране в одно и то же время, одно в левом верхнем углу, другое — в правом нижнем (рис. 17.35).
Рис. 17.35. Исходное положение, с которого начинается анимация