Вандад Нахавандипур - iOS. Приемы программирования
Рис. 17.35. Исходное положение, с которого начинается анимация
В этом примере изображение из верхнего левого угла будет называться image 1, а из правого нижнего — image 2.
Как уже упоминалось, в этом коде мы собираемся создать два изображения, в верхнем левом и правом нижнем углах. Далее image 1 станет двигаться по направлению к image 2 и будет так перемещаться на протяжении 3 секунд, а потом медленно исчезнет. Когда image 1 начнет движение, станет двигаться и image 2 — оно пойдет в верхний левый угол экрана, где изначально находилось изображение image 1. Опять же мы хотим, чтобы анимация изображения image 2 завершилась за 3 секунды и оно медленно исчезло. Когда вы запустите этот код на устройстве или симуляторе iOS, такая анимация будет выглядеть очень классно. Теперь расскажу, как все это запрограммировать.
1. В верхней части. m-файла нашего контроллера вида определим два вида с изображениями:
@interface ViewController ()
@property (nonatomic, strong) UIImageView *xcodeImageView1;
@property (nonatomic, strong) UIImageView *xcodeImageView2;
@end
@implementation ViewController
2. В методе экземпляра viewDidLoad, относящемся к контроллеру вашего вида, инициализируем оба этих вида с изображениями и помещаем их в основной вид:
— (CGRect) bottomRightRect{
CGRect endRect;
endRect.origin.x = self.view.bounds.size.width — 100;
endRect.origin.y = self.view.bounds.size.height — 100;
endRect.size = CGSizeMake(100.0f, 100.0f);
return endRect;
}
— (void) viewDidLoad{
[super viewDidLoad];
UIImage *xcodeImage = [UIImage imageNamed:@"Xcode.png"];
self.xcodeImageView1 = [[UIImageView alloc]
initWithImage: xcodeImage];
self.xcodeImageView2 = [[UIImageView alloc]
initWithImage: xcodeImage];
/* Просто задаем размеры так, чтобы изображения уменьшились. */
[xcodeImageView1 setFrame: CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[self.xcodeImageView2 setFrame: [self bottomRightRect]];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview: self.xcodeImageView1];
[self.view addSubview: self.xcodeImageView2];
}
3. Реализуем для нашего контроллера вида метод экземпляра, который называется startTopLeftImageViewAnimation. Как понятно из названия[12], данный метод будет выполнять анимацию для изображения image 1, перемещая его из верхнего левого угла экрана в нижний правый, а изображение тем временем будет медленно исчезать. Такое исчезновение достигается установкой альфа-значения в 0:
— (void) startTopLeftImageViewAnimation{
/* Начинаем с верхнего левого угла. */
[self.xcodeImageView1 setFrame: CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[self.xcodeImageView1 setAlpha:1.0f];
[UIView beginAnimations:@"xcodeImageView1Animation"
context:(__bridge void *)self.xcodeImageView1];
/* Трехсекундная анимация */
[UIView setAnimationDuration:3.0f];
/* Получаем анимационные делегаты. */
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop: finished: context:)];
/* Заканчиваем в нижнем правом углу. */
[self.xcodeImageView1 setFrame: CGRectMake(220.0f,
350.0f,
100.0f,
100.0f)];
[self.xcodeImageView1 setAlpha:0.0f];
[UIView commitAnimations];
}
4. Когда анимация какого-либо из этих видов остановится, мы удалим данный вид из иерархии родительских видов, так как больше в нем не нуждаемся. Как было показано в методе startTopLeftImageViewAnimation, мы передали селектор делегата методу класса setAnimationDidStopSelector:, относящемуся к классу UIView. Этот селектор будет вызываться после окончания анимации image 1 (как было показано ранее) и image 2 (как мы вскоре увидим). Вот реализация этого селектора делегата:
— (void)imageViewDidStop:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
UIImageView *contextImageView = (__bridge UIImageView *)paramContext;
[contextImageView removeFromSuperview];
}
5. Кроме того, нам понадобится метод для анимирования image 2. Между написанием анимационных методов для image 2 и image 1 есть небольшая разница. Я хочу начать анимацию image 2, немного не дожидаясь завершения анимации image 1. Следовательно, если анимация image 1 завершается за 3 секунды, то я начну анимировать image 2 со второй секунды анимации image 1. Таким образом, анимация image 2 начнется еще до того, как изображение image 1 дойдет до нижнего правого угла экрана и исчезнет. Чтобы достичь такого результата, я установлю начало анимации для обоих изображений на одно и то же время, но перед началом анимации image 2 поставлю двухсекундную задержку. Итак, если обе анимации начнутся в час дня, то для изображения image 1 начальным моментом анимации будет 13:00:00, а конечным — 13:00:03. Соответствующие значения image 2 будут равны 13:00:02 и 13:00:05. Вот как будет происходить анимация image 2:
— (void) startBottomRightViewAnimationAfterDelay:(CGFloat)paramDelay{
/* Начинаем с нижнего правого угла. */
[self.xcodeImageView2 setFrame: [self bottomRightRect]];
[self.xcodeImageView2 setAlpha:1.0f];
[UIView beginAnimations:@"xcodeImageView2Animation"
context:(__bridge void *)self.xcodeImageView2];
/* Трехсекундная анимация */
[UIView setAnimationDuration:3.0f];
[UIView setAnimationDelay: paramDelay];
/* Получаем анимационные делегаты. */
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop: finished: context:)];
/* Заканчиваем в верхнем левом углу. */
[self.xcodeImageView2 setFrame: CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[self.xcodeImageView2 setAlpha:0.0f];
[UIView commitAnimations];
}
6. И последнее, но немаловажное замечание. Как только вид отобразится, мы должны запустить методы startTopLeftImageViewAnimation и startBottomRightViewAnimationAfterDelay::
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
[self startTopLeftImageViewAnimation];
[self startBottomRightViewAnimationAfterDelay:2.0f];
}
17.15. Анимирование и масштабирование видов
Постановка задачи
Требуется возможность анимировать виды и масштабировать их в сторону увеличения или уменьшения.
Решение
Создайте для вида аффинное преобразование и используйте анимационные методы UIView для сопровождения масштабирования анимацией.
Обсуждение
Перед дальнейшей работой настоятельно рекомендую перечитать раздел 17.14.
Чтобы масштабировать вид, анимируя его при этом, можно либо применить к виду преобразование масштабирования в анимационном блоке (см. раздел 17.12), либо просто увеличить высоту и/или ширину вида.
Рассмотрим, как изменять масштаб вида, применяя к нему преобразование масштабирования:
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
/* Помещаем вид с изображением в центре основного вида данного
контроллера вида. */
self.xcodeImageView.center = self.view.center;
/* Убеждаемся, что к этому виду с изображением не применяется никакого
преобразования сдвига. */
self.xcodeImageView.transform = CGAffineTransformIdentity;
/* Начинаем анимацию. */
[UIView beginAnimations: nil
context: NULL];
/* Анимация продлится 5 секунд. */
[UIView setAnimationDuration:5.0f];
/* Вдвое увеличиваем вид с изображением в ширину и в длину. */
self.xcodeImageView.transform = CGAffineTransformMakeScale(2.0f,
2.0f);
/* Выполняем анимацию. */
[UIView commitAnimations];
}
В этом коде используется аффинное преобразование масштабирования, в результате которого вид с изображением становится в два раза больше по сравнению с исходными размерами. Самое большое достоинство такой операции заключается в том, что в ходе масштабирования начало координат (центр) при увеличении или уменьшении совпадает с началом координат (центром) самого вида. Предположим, что центр вашего вида расположен на экране в точке с координатами (100; 100), а вы хотите масштабировать вид, вдвое увеличив его ширину и высоту. В результате центр вида так и останется в точке (100; 100), в то время как сам вид увеличится в два раза. Если бы мы увеличивали вид, сначала специально добавив ему ширины, а потом высоты, то вид, который получился бы в итоге, находился бы немного не в той точке экрана, где был исходный вид. Это объясняется тем, что, изменяя высоту и ширину рамок вида, вы одновременно изменяете значения x и y контура вида, хотите вы того или нет. Поэтому вид с изображением не будет масштабироваться относительно своего центра. Исправление такой проблемы выходит за рамки этой книги, но вы можете самостоятельно разобраться с этой задачей — может быть, вам удастся найти решение. Дам одну подсказку: можно параллельно запустить две анимации. Одна из них будет изменять длину и ширину вида, а другая — перемещать центр вида.