Прокрутка UILabel Animation не запускается после определенного изменения содержимого - PullRequest
0 голосов
/ 10 октября 2011

Я создаю некую метку прокрутки, которая в основном представляет собой UIView, содержащий метку, которую я анимирую, заставляя дочернюю метку переходить назад и вперед, если текст больше, чем UIView;

@implementation ScrollLabel

static float DEFAULT_SPEED_IN_PIXELS_PER_SECOND = 30.0;
static float DEFAULT_ANIMATION_DELAY = 2.0;

#pragma mark - Properties

#pragma mark - Initialization and Memory Management

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    label1 = [[UILabel label] retain];
    [label1 setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
    [label1 setBackgroundColor:[UIColor clearColor]];
    [label1 setNumberOfLines:1];

    [self addSubview:label1];

    speedInPixelsPerSecond = DEFAULT_SPEED_IN_PIXELS_PER_SECOND;
    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;

    scrollType = theScrollType;
    //[self setBackgroundColor:[UIColor greenColor]];
        [self setClipsToBounds:YES];

    return self;
}

- (void)dealloc
{
    [label1 release];

    [super dealloc];
}

#pragma mark - Public Static Methods

#pragma mark - Public Instance Methods

// Implement this method if you need more precise control over the layout of your subviews than the autoresizing behaviors provide.
- (void)layoutSubviews
{   
    [super layoutSubviews];

    [self setLabelSize];

    [self checkToStartOrStopAnimating];
}

- (void)setText:(NSString *)text
{
    if( text == [label1 text] ) return;

    [self stopAnimating];   

    [label1 setText:text];

    [self setNeedsLayout];

    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;
}

- (void)checkToStartOrStopAnimating
{   
    if ([self shouldAnimate])
    {
        [self startAnimating];
    }
    else
    {
        [self stopAnimating];
    }
}

- (void)setLabelSize
{
    [label1 sizeToFit];
    [label1 setFrame:CGRectMake(0, 0, [label1 frame].size.width, [label1 frame].size.height)];

}

- (void)startAnimating
{
    if (!animating)
    {
        animating = YES;

        [self animateForwards];
    } 
}

- (void)stopAnimating
{   
    if(animating)
    {
        animating = NO;

        [[label1 layer] removeAllAnimations];
    }
}

- (BOOL)isAnimating
{
    return animating;
}

#pragma mark - Private Methods

- (void)animateForwards
{
    float distanceToTravel = [label1 frame].size.width - [self frame].size.width;

    if(distanceToTravel > 0 && animating )
    {
        CGRect rect = [label1 frame];

        [UIView animateWithDuration:distanceToTravel / speedInPixelsPerSecond 
                delay:scrollAnimationDelay 
                options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear
                animations:^(void) 
                {

                    [label1 setFrame:CGRectMake(rect.size.width - self.size.width, 0, rect.size.width, rect.size.height)];
                } 
                completion:^(BOOL finished) 
                {
                    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;

                    if(finished)
                    {
                        [self animateBackwards];                    
                    } 
                    else
                    {
                        [self stopAnimating];
                        [self setNeedsLayout];
                    }               
                }];
    }
    else
    {
        [self stopAnimating];
        [self setNeedsLayout];
    }
}

- (void)animateBackwards
{
    float distanceToTravel = [label1 frame].size.width - [self frame].size.width;

    if (distanceToTravel > 0 && animating) 
    {
        CGRect rect = [label1 frame];
        [UIView animateWithDuration:distanceToTravel / speedInPixelsPerSecond 
                delay:scrollAnimationDelay 
                options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear
                animations:^(void) 
                {
                    [label1 setFrame:CGRectMake(0, 0, rect.size.width, rect.size.height)];
                } 
                completion:^(BOOL finished) 
                {
                    if (finished)
                    {
                        [self animateForwards];
                    }
                    else
                    {
                        [self stopAnimating];
                        [self setNeedsLayout];
                    }
                }];
    }
    else 
    {
        [self stopAnimating];
        [self setNeedsLayout];
    }
}

- (BOOL) shouldAnimate
{ 
    return [label1 frame].size.width > [self frame].size.width && [self frame] > 0.0;
}

@end

За исключением случаев, когда анимация запущена (то есть когда текст занимает больше места, чем широкий вид контейнера), если вы измените текст на что-то другое, что также займет больше места, чем широкий вид контейнера, так или иначерегрессия в некоторое состояние потока, в котором все анимации заканчиваются на Finish = NO (даже если метка и родительское представление имеют правильный размер), что, в свою очередь, вызывает вызов layoutSubviews, что, в свою очередь, приводит к повторному запуску анимациии закончить снова с отделкой = НЕТ.Обратите внимание, что этого не происходит, когда текст действительно помещается в рамку родительского элемента.

Я почти не понимаю, почему это происходит;Очевидно, я могу догадаться, что после установки текста что-то не правильно установлено, но я не могу понять, что это такое. Спрашивается в более общей форме , но, конечно, нет окончательных ответов.

1 Ответ

0 голосов
/ 18 октября 2011

Я решил проблему; очевидно, когда текст был задан, анимация остановилась и layoutSubViews вызвал правильно, в то время как анимация останова перешла бы на finished = NO и, таким образом, вызвала layoutSubViews, чтобы снова запустить анимацию. Решение состоит в том, чтобы проверить, идет ли анимация, и вызывать layoutSubviews только тогда, когда анимация не выполняется, в противном случае полагайтесь на отмену анимации и вызов layoutSubviews.

@implementation ScrollLabel

static float DEFAULT_SPEED_IN_PIXELS_PER_SECOND = 30.0;
static float DEFAULT_ANIMATION_DELAY = 2.0;

#pragma mark - Properties

#pragma mark - Initialization and Memory Management

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    label1 = [[UILabel label] retain];
    [label1 setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
    [label1 setBackgroundColor:[UIColor clearColor]];
    [label1 setNumberOfLines:1];

    [self addSubview:label1];

    speedInPixelsPerSecond = DEFAULT_SPEED_IN_PIXELS_PER_SECOND;
    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;

    scrollType = theScrollType;
    //[self setBackgroundColor:[UIColor greenColor]];
        [self setClipsToBounds:YES];

    return self;
}

- (void)dealloc
{
    [label1 release];

    [super dealloc];
}

#pragma mark - Public Static Methods

#pragma mark - Public Instance Methods

// Implement this method if you need more precise control over the layout of your subviews than the autoresizing behaviors provide.
- (void)layoutSubviews
{   
    [super layoutSubviews];

    [self setLabelSize];

    [self checkToStartOrStopAnimating];
}

- (void)setText:(NSString *)text
{
    if( text == [label1 text] ) return;

    [label1 setText:text];

    if(animating) 
{
    [self stopAnimating];
} 
else 
{
    [self setNeedsLayout];
}

    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;
}

- (void)checkToStartOrStopAnimating
{   
    if ([self shouldAnimate])
    {
        [self startAnimating];
    }
    else
    {
        [self stopAnimating];
    }
}

- (void)setLabelSize
{
    [label1 sizeToFit];
    [label1 setFrame:CGRectMake(0, 0, [label1 frame].size.width, [label1 frame].size.height)];

}

- (void)startAnimating
{
    if (!animating)
    {
        animating = YES;

        [self animateForwards];
    } 
}

- (void)stopAnimating
{   
    if(animating)
    {
        animating = NO;

        [[label1 layer] removeAllAnimations];
    }
}

- (BOOL)isAnimating
{
    return animating;
}

#pragma mark - Private Methods

- (void)animateForwards
{
    float distanceToTravel = [label1 frame].size.width - [self frame].size.width;

    if(distanceToTravel > 0 && animating )
    {
        CGRect rect = [label1 frame];

        [UIView animateWithDuration:distanceToTravel / speedInPixelsPerSecond 
                delay:scrollAnimationDelay 
                options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear
                animations:^(void) 
                {

                    [label1 setFrame:CGRectMake(rect.size.width - self.size.width, 0, rect.size.width, rect.size.height)];
                } 
                completion:^(BOOL finished) 
                {
                    scrollAnimationDelay = DEFAULT_ANIMATION_DELAY;

                    if(finished)
                    {
                        [self animateBackwards];                    
                    } 
                    else
                    {
                        [self stopAnimating];
                        [self setNeedsLayout];
                    }               
                }];
    }
    else
    {
        [self stopAnimating];
    }
}

- (void)animateBackwards
{
    float distanceToTravel = [label1 frame].size.width - [self frame].size.width;

    if (distanceToTravel > 0 && animating) 
    {
        CGRect rect = [label1 frame];
        [UIView animateWithDuration:distanceToTravel / speedInPixelsPerSecond 
                delay:scrollAnimationDelay 
                options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear
                animations:^(void) 
                {
                    [label1 setFrame:CGRectMake(0, 0, rect.size.width, rect.size.height)];
                } 
                completion:^(BOOL finished) 
                {
                    if (finished)
                    {
                        [self animateForwards];
                    }
                    else
                    {
                        [self stopAnimating];
                        [self setNeedsLayout];
                    }
                }];
    }
    else 
    {
        [self stopAnimating];
    }
}

- (BOOL) shouldAnimate
{ 
    return [label1 frame].size.width > [self frame].size.width && [self frame] > 0.0;
}

@end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...