2011-10-10 130 views
0

林建設某種滾動標籤,這基本上是一個包含我的動畫標記一個UIView,造成孩子標籤去來回如果文本比UIView的大;滾動的UILabel動畫無法啓動

@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被調用,反過來導致動畫重新開始,並以finish = NO結束。 請注意,當文本實際符合父級的框架時,不會發生這種情況。

林幾乎一無所知到爲什麼會發生;我可以很明顯地猜出設置文本後沒有正確設置,但我無法弄清楚是什麼。 Asked in a more general form,但當然沒有確鑿的答案。

回答

0

我解決了這個問題;顯然當文本得到了設定,動畫停止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