I'm trying to animate an indicator to an empty form field so I'm using the method below to animate to a position, reverse the animation, and repeat. In the simulator this works fine, on my 3GS it looks like there is a flicker right when the completion block is called. The indicator is briefly shown at the middle position rather than back at it's origin.
Any thoughts on why this is happening? Thanks.
- (void)bounceFormIndicator {
if (formIndicator.superview == nil) {
return;
}
int bounceDistance = 24;
[UIView animateWithDuration:0.6
delay:0
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect indicatorFrame = formIndicator.frame;
indicatorFrame.origin.x += bounceDistance;
formIndicator.frame = indicatorFrame;
}completion:^(BOOL finished){
CGRect indicatorFrame = formIndicator.frame;
indicatorFrame.origin.x -= bounceDistance;
formIndicator.frame = indicatorFrame;
[self bounceFormIndicator];
}];
}
I had the same problem, and went to Apple DTS to help with a workaround.
As per DTS, this 'flickering' effect, or snap-back effect is the expected behaviour... I thought that I was doing something wrong with my project for a long time.
In particular it is this way because the documentation states, for
UIViewAnimationOptionAutoreverse Run the animation backwards and forwards.
Must be combined with the UIViewAnimationOptionRepeat option.
In order to get the flicker to go away, I had to do 2 things.
My implementation was dynamic, so you might not have to implement the first step, but I'll keep it in here just for reference.
First, I checked to see if UIViewAnimationOptionAutoreverse
was part of the options I was going to pass into my animation, and UIViewAnimationOptionRepeat
was not... If so, I stripped it from the options by adding a line like:
animationOptions &= ~UIViewAnimationOptionAutoreverse;
To create the reversing animation without repeating, I added an opposite UIView animation as my completion block. I also inverted the easing if it was either UIViewAnimationOptionCurveEaseIn
or UIViewAnimationOptionCurveEaseOut
...
The code from my project follows:
The statement that strips the autoreverse option from an object's animationOptions:
if ((animationOptions & AUTOREVERSE) == AUTOREVERSE) {
self.shouldAutoreverse = YES;
animationOptions &= ~AUTOREVERSE;
}
An example of an overridden property setter that handles an animation:
-(void)setCenter:(CGPoint)center {
CGPoint oldCenter = CGPointMake(self.center.x, self.center.y);
void (^animationBlock) (void) = ^ { super.center = center; };
void (^completionBlock) (BOOL) = nil;
BOOL animationShouldNotRepeat = (self.animationOptions & REPEAT) != REPEAT;
if(self.shouldAutoreverse && animationShouldNotRepeat) {
completionBlock = ^ (BOOL animationIsComplete) {
[self autoreverseAnimation:^ { super.center = oldCenter;}];
};
}
[self animateWithBlock:animationBlock completion:completionBlock];
}
The completion method called for in the case of reversing without repeating:
-(void)autoreverseAnimation:(void (^)(void))animationBlock {
C4AnimationOptions autoreverseOptions = BEGINCURRENT;
if((self.animationOptions & LINEAR) == LINEAR) autoreverseOptions |= LINEAR;
else if((self.animationOptions & EASEIN) == EASEIN) autoreverseOptions |= EASEOUT;
else if((self.animationOptions & EASEOUT) == EASEOUT) autoreverseOptions |= EASEIN;
[UIView animateWithDuration:self.animationDuration
delay:0
options:autoreverseOptions
animations:animationBlock
completion:nil];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With