1
votes

I have some sort of counter built from multiple UIScrollViews containing images of numbers. Counter is periodically updated with old and new number and animation duration. Update is actually for loop always incrementing counter for +1. When I put this into animation block, animation is performed like I just updated it to toValue, like there is no for loop.

What I want is animation to be performed in linear manner, I want to see every number (in case animation is not too fast which isn't). In some weird scenario, counter just jumps to some random number in [fromValue, toValue] interval without animation, and then animated jumps to toValue.

Any suggestions? Here is some code

- (void) setDigit:(UIScrollView*)digit withValue:(int)value
{
    CGFloat height = digit.frame.size.height;
    [digit setContentOffset:CGPointMake(0, height * value) animated:NO];
}

- (void) updateValue:(int) value
{
     for (int i = 5; i >= 0; i--)
     {
        int a = value % 10;
        value = value / 10;

        [self setDigit:[digits objectAtIndex:i] withValue:a];
     }
}

- (void) transitFromValue:(int)fromValue toValue:(int)toValue withDuration:(float)duration
{
    [UIView animateWithDuration:duration 
                      delay:0.0 
                    options:UIViewAnimationCurveLinear
                 animations:^ {
                     for (int tValue = fromValue; tValue <= toValue; tValue++)
                     {
                         [self updateValue:tValue];
                     }

                 } 
                 completion:^(BOOL finished) {
                 }];

}
2

2 Answers

3
votes

Final values of properties set in animation block are what system is gonna use for animations. You can set thousands of different values through for loop, but only the last one will be used for animation.

Your best solution is a recursive method that animates one step and gets called again when it's done.

- (void) transitFromValue:(int)fromValue toValue:(int)toValue withDuration:(float)duration
{
    [UIView animateWithDuration:duration 
                      delay:0.0 
                    options:UIViewAnimationCurveLinear
                 animations:^ {
                     [self updateValue:fromValue + 1];
                 } 
                 completion:^(BOOL finished) {
                     if (finished && fromValue + 1 < toValue) {
                         [self transitFromValue:fromValue + 1 toValue:toValue withDuration:duration];
                     }
                 }];

}
1
votes

I think that the problem is that animation does not start when you start the for loop. It goes thru the bolck and then sees the last value and animates to that value.. But I'm not 100% sure if that is a problem. Maybe if you try to do this:

int tValue=fromValue;
[UIView animateWithDuration:duration 
                      delay:0.0 
                    options:UIViewAnimationCurveLinear
                 animations:^ {
                     [self updateValue:tValue];
                 } 
                 completion:^(BOOL finished) {
                 tValue++;
                 }];
[UIView animateWithDuration:duration 
                      delay:0.0 
                    options:UIViewAnimationCurveLinear
                 animations:^ {
                     [self updateValue:tValue];
                 } 
                 completion:^(BOOL finished) {
                 tValue++;
                 }];

or put that animations in for loop