douglasd3
douglasd3

Reputation: 761

Animate view repeatedly and continuously

I'm simulating some effects, like leafs falling, snow and rain. My first call was to use CAEmitterLayer, that works very well, but i need to render the layer in context to save as an image, and that seens impossible or, at least, very complicated.

So i am working with some view animations. I need to continuously animate my imageViews so it can fall through screen and reappear on top of it, each one with diffenrent speed.

So i relocate each imageView on screen with animateWithDuration and when animation is done i call the method that do that recursively from completion block so the imageview can make it's way to the end of screen. Once an imageView reachs the end of screen i relocate it on top.

The problem is when animation is over my imageView stops a little bit until the completion block calls the method recursively, i want it to be continuously.

My code generates random position for each imageView, and my animation duration is very short so i can always update imageView's location in case the user tap the button to save the view as an image.

Anyway, here is my code:

- (void)effectOnObject:(UIImageView *)object{
    NSInteger initialX;
    NSInteger initialy;
    CGFloat duration;

    //the object have reached the end of screen
    if (object.frame.origin.y >= self.frame.size.height) {
        //generate random position to relocate the object on x axis
        initialX = arc4random() % 321;

        //generate random position to relocate the object on y axis (little bit above top of screen)
        initialy = ((NSInteger)-object.frame.size.height) - arc4random() % 11;

        //duration 0 so the object can be replaced without animation
        duration = 0.0;
    }
    else{
        initialX = object.frame.origin.x;

        //this change the speed of object
        initialy = object.frame.origin.y + 10

        //setted duration to short time
        duration = 0.01;
    }

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionAllowAnimatedContent 
     animations:^{
        [object setFrame:CGRectMake(initialX, initialy, object.frame.size.width, object.frame.size.height)];
     }
     completion:^(BOOL completed){
         //recursively call
         [self effectOnObject:object];                   
      }];
}

- (void)startEffect{

    //initiate effect on each imageView
    for (UIImageView *object in self.subviews) {
        [self effectOnObject:object];   
    }    
}

How can i make this animation repeatedly and continuously, without the gap when the method is called recursively from completion block and the animation restarts?

Upvotes: 0

Views: 1268

Answers (2)

Timothy Moose
Timothy Moose

Reputation: 9915

You don't need to do the animation with 0 duration when the object reaches the end of the screen. Just test for this in your completion block and relocate the view before calling recursively. Also, a duration of 0.01 seems a bit extreme (100 frames per second). Perhaps a more reasonable value like 0.1 would help.

Something like this:

- (void)effectOnObject:(UIImageView *)object{

    //setted duration to short time
    CGFloat duration = 0.1;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionAllowAnimatedContent
                     animations:^{

                         NSInteger initialX = object.frame.origin.x;

                         //this change the speed of object
                         NSInteger initialy = object.frame.origin.y + 10;

                         [object setFrame:CGRectMake(initialX, initialy, object.frame.size.width, object.frame.size.height)];
                     }
                     completion:^(BOOL completed){

                         NSInteger initialX = arc4random() % 321;

                         //generate random position to relocate the object on y axis (little bit above top of screen)
                         NSInteger initialy = ((NSInteger)-object.frame.size.height) - arc4random() % 11;

                         [object setFrame:CGRectMake(initialX, initialy, object.frame.size.width, object.frame.size.height)];

                         //recursively call
                         [self effectOnObject:object];
                     }];
}

Upvotes: 1

hfossli
hfossli

Reputation: 22972

From what I read briefly you should check out CAReplicatorLayer. It is perfect for repeating stuff! Only issue I can think of is that the transform and values have to be incremental...

Upvotes: 0

Related Questions