UIView beginAnimations в одном экземпляре класса запускает beginAnimations в другом экземпляре того же класса
Надеюсь, что вы можете помочь или объяснить, что здесь происходит, так как я не очень хорошо UIGraphics
контексты.
Я определил класс, который автоматически прокручивает метку назад и вперед в своем фрейме, когда текст метки слишком длинный для данного пространства в основном представлении контроллеров представления.
Он состоит из прокрутки, которая соответствует выделенному пространству в родительском представлении, и содержит UILabel
(в подклассе), размер которого соответствует размеру текста.
(UILabel - это подпредставление в родительском представлении прокрутки).
Scrollview фиксирует анимацию, которая прокручивает UILabel влево -> вправо, затем, когда анимация заканчивается, я запускаю делегата.
(void)animationDidStop:animationID(NSString*)finished:(NSNumber *)finished context:(void *)context'
который сбрасывает некоторые числа и перезапускает анимацию, прокручивая ее в обратном направлении вправо -> влево
Это работает очень хорошо.
Однако, если я добавлю еще один экземпляр этой "метки прокрутки" где-нибудь еще в главном представлении контроллеров представления, то одна из анимаций остановится, и AnimationDidStop
Делегат уволен, он заново запускает анимацию для другого объекта метки "прокрутка".
Я попробовал следующее, чтобы изолировать запуск анимации без каких-либо положительных результатов. Передача контекста представлений и идентификатора beginAnimations, а затем их захват в (void)animationDidStop
метод... не имеет никакого значения. Это заставляет меня думать, что метод, кажется, не принимает
Ниже приведен код, который выполняет анимацию, и код, который перезапускает его в другом направлении.
Как я уже сказал, он работает очень хорошо сам по себе, но когда на экране одновременно находится более 1 экземпляра этого класса, beginAnimations, похоже, срабатывает для обоих экземпляров.
Надеюсь, вы можете объяснить, почему. Благодарю.
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus {
NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:((UILabel*)_textLabel).text context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(@"Animation Did stop context = %@",context);
if ([animationID isEqualToString:((UILabel*)_textLabel).text]){
static BOOL forward = NO;
if ([finished boolValue]) {
CGPoint origin;
CGPoint terminal_origin;
if (forward){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
}
forward = !forward;
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin];
}
}
}
РЕДАКТИРОВАТЬ: Добавлено 28/5/14 @ 13:14 После того, как A-Lives посоветовал насчет использования статики... изменил код, чтобы использовать его метку в качестве флага, чтобы подсказать изменение направления при прокрутке. ЭТО ИСПРАВИЛО ПРОБЛЕМУ
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{
if (!direction)direction = @"FORWARD";
NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:direction context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(@"Animation Did stop context = %@",context);
NSString *direction;
CGPoint origin;
CGPoint terminal_origin;
if (![animationID isEqualToString:@"FORWARD"]){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = @"FORWARD";
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = @"BACKWARD";
}
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}
1 ответ
Проблема заключалась в том, что мы забыли, что статика - это обычные статические переменные C, которые доступны по всему приложению. (то есть, не инкапсулированные в области, которая их определяла.)
Несколько экземпляров одного и того же класса все читают и записывают значения в одну и ту же переменную, вызывая непредсказуемое поведение.
Решение. Передайте сообщения на уровне экземпляра, чтобы контролировать переключаемые действия, когда вы не можете гарантировать, что ваш класс является единственным.
Модифицированный рабочий код:
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{
if (!direction)direction = @"FORWARD";
NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:direction context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(@"Animation Did stop context = %@",context);
NSString *direction;
CGPoint origin;
CGPoint terminal_origin;
if (![animationID isEqualToString:@"FORWARD"]){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = @"FORWARD";
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = @"BACKWARD";
}
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}