Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6716143
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T08:41:53+00:00 2026-05-26T08:41:53+00:00

Im building some sort of a scroll label, which basically is a UIView containing

  • 0

Im building some sort of a scroll label, which basically is a UIView containing a label that i animate, causing the child Label to go back and forth if the text is larger than the 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

Except when the animation is running (that is when the text takes up more space than the container view is wide), if you change the text to something else that also takes up more space than the container view is wide, somehow the thing is regressing into some state of flux in which all of the animations end with finish = NO (even though the label and parent view has correct size), which of course in turn causes layoutSubviews to be called, which in turn causes the animation to start again and end again with finish = NO.
Note that this doesn’t happen when the text actually fits in the frame of the parent.

Im pretty much clueless to why it happens; i can obviously guess that something isn’t properly set after setting the text, but i can’t figure out what that something is. Asked in a more general form, but of course no conclusive answers.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T08:41:53+00:00Added an answer on May 26, 2026 at 8:41 am

    I solved the problem; apparently when the text got set, the animation stopped and layoutSubViews called properly, while the stopping animation would go finished = NO and thus call layoutSubViews again restarting the animation. Solution is to check if an animation is going, and only call layoutSubviews when no animation is currently running, else rely on the animation to cancel and that to call 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
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm building some sort of censoring app. I've gotten so far that i can
I'm building an interactive movie of some sort , having more video clips that
I'm building a physics engine and i had some sort of pseudo-verlet thing going
Is there drop-in replacement for ActiveRecord that uses some sort of Object Store? I
I am building a gaming system where many players can play some sort of
I was wondering what are the general steps required in building some sort of
So, hypothetically, I'm building some sort of real estate application in C#. For each
I'm building a small application that highly depends on anonymous user voting on some
This is a 2 part question. 1) Is there some sort of program that
I'm in the process of building a rails app that will basically wrap around

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.