huong
huong

Reputation: 4564

iOS - Animation of many different views

I'm trying to implement animations on many different UIView and UIImageView to make them consecutively fade in, move up and fade out one by one. This includes a very long series of animation, and I use simple UIView animation blocks with delay to make the moves happen one after another like this (which is a very small excerpt of the whole animation flow):

// Start animation
    [UIView animateWithDuration:0.1
                          delay:0.0
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon1Image.alpha = 0.3;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.1
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon1Image.frame = CGRectMake(33, 56, 73, 73);
                         redIcon1Image.alpha = 1;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.2
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon2Image.alpha = 0.3;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.3
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon2Image.frame = CGRectMake(127, 33, 68, 68);
                         redIcon2Image.alpha = 1;
                         doc1Image.alpha = 0.3;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.4
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         doc1Image.alpha = 1;
                         redIcon2Image.frame = CGRectMake(123, 28, 73, 73);
                         redIcon3Image.alpha = 0.3;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.5
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon3Image.frame = CGRectMake(221, 53, 68, 68);
                         redIcon3Image.alpha = 1;
                         doc2Image.alpha = 0.3;
                     }
                     completion:nil];
    [UIView animateWithDuration:0.1
                          delay:0.6
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         redIcon3Image.frame = CGRectMake(218, 56, 73, 73);
                         doc2Image.alpha = 1;
                         doc3Image.alpha = 0.2;
                         glowView.alpha = 0.2;
                     }
                     completion:nil];

    [UIView animateWithDuration:0.1
                          delay:0.7
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         doc3Image.alpha = 0.6;
                         glowView.alpha = 0.5;
                     }
                     completion:nil];

    [UIView animateWithDuration:0.1
                          delay:0.8
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         doc3Image.alpha = 1;
                         glowView.alpha = 0.8;
                     }
                     completion:nil];

The thing is, although some views are set to be visible (alpha > 0) with delay, I can still see them being visible right when the animation starts. Could there be something wrong with the way I set the delay? I can't use the completion block in this situation because it would make a very complicated nested animation block. What should I do to make sure the animation runs smoothly? Please suggest and thanks.

Edit: I did set every view to be invisible, i.e. alpha = 0.0, before starting the animation. Also, I put all the animation in my viewDidLoad method.

Upvotes: 0

Views: 1118

Answers (3)

Logan
Logan

Reputation: 53112

I had an idea that might work,

Step 1: Declare an Array Property & Counter property

NSArray * blockArray;
int currentAnimationBlockIndex;

Step 2: Declare Animation Blocks

void (^block1)(void) = ^{
    redIcon1Image.alpha = 0.3;
};
void (^block2)(void) = ^{
    redIcon1Image.frame = CGRectMake(33, 56, 73, 73);
    redIcon1Image.alpha = 1;
};
void (^block3)(void) = ^{
    redIcon2Image.alpha = 0.3;
};
void (^block4)(void) = ^{
    redIcon2Image.frame = CGRectMake(127, 33, 68, 68);
    redIcon2Image.alpha = 1;
    doc1Image.alpha = 0.3;
};
void (^block5)(void) = ^{
    doc1Image.alpha = 1;
    redIcon2Image.frame = CGRectMake(123, 28, 73, 73);
    redIcon3Image.alpha = 0.3;
};
void (^block6)(void) = ^{
    redIcon3Image.frame = CGRectMake(221, 53, 68, 68);
    redIcon3Image.alpha = 1;
    doc2Image.alpha = 0.3;
};
void (^block7)(void) = ^{
    redIcon3Image.frame = CGRectMake(218, 56, 73, 73);
    doc2Image.alpha = 1;
    doc3Image.alpha = 0.2;
    glowView.alpha = 0.2;
};
void (^block8)(void) = ^{
    doc3Image.alpha = 0.6;
    glowView.alpha = 0.5;
};
void (^block9)(void) = ^{
    doc3Image.alpha = 1;
    glowView.alpha = 0.8;
    NSLog(@"9");
};

Step 3: Add Blocks To Array & Set Counter to 0

blockArray = [[NSArray alloc]initWithObjects:block1, block2, block3, block4, block5, block6, block7, block8, block9, nil];

currentAnimationBlockIndex = 0;

Step 4: Add Animation Method

- (void) animateThroughBlocks {
    void (^animationBlock)(void) = blockArray[currentAnimationBlockIndex];
    [UIView animateWithDuration:0.1
                          delay:0.0
                        options:UIViewAnimationOptionCurveLinear
                     animations:animationBlock
                     completion:^(BOOL finished) {
                         if (finished) {
                             currentAnimationBlockIndex = currentAnimationBlockIndex + 1;
                             if (currentAnimationBlockIndex == blockArray.count) {
                                 // completed animations!
                                 // reset counter
                                 currentAnimationBlockIndex = 0;
                             }
                             else {
                                 [self animateThroughBlocks];
                             }
                         }
                     }];

}

Step 5: Call Method

[self animateThroughBlocks];

Let me know how this goes for you!

Upvotes: 1

Cyrille
Cyrille

Reputation: 25144

This is how you could chain animations easily: by declaring them as an array of animation blocks. Every completion block calls the next animation until the array is "finished".

Completely untested code, but that should give you the general idea:

UIView *view1, *view2, *view3;
NSArray *animations = @[
    ^{ view1.alpha = 1; view2.alpha = .3; },
    ^{ view2.alpha = 1; },
    ^{ view3.alpha = 0.5; }
];
void (^animate)(NSInteger index) = ^(NSInteger index){
    [UIView animateWithDuration:.1 animations:^{
        void (^animationBlock)() = animations[index];
        animationBlock();
    } completion:^(BOOL finished) {
        if (index < animations.count)
            animate(index+1);
    }];
};
animate(0);

I'm not really sure this is how you make recursive blocks (after all, that's what it is) from a memory-management point of view, but the idea is here.

Of course in this scenario, all animations have the same duration. You could build another NSArray (having the same length as animations) with the durations as NSNumbers, and use them as the duration parameter.

Upvotes: 1

Matthew Gillingham
Matthew Gillingham

Reputation: 3429

Are you setting the alpha of views to 0.0 before the animation starts? e.g.

redIcon1Image.alpha = 0.0;

[UIView animateWithDuration:0.1
                      delay:0.0
                    options:UIViewAnimationOptionCurveLinear
                 animations:^{
                     redIcon1Image.alpha = 0.3;
                 }
                 completion:nil];

It isn't clear if you are doing so from your description, but that might explain why the views are initially visible.

Upvotes: 0

Related Questions