问题
I have a number of images I run continuous animations on. How does one update these running animations smoothly so that there is no visible transition between them, unless part of the animation.
e.g. rotating and scaling an image, and then updating the animation to rotate as it was, but scale up slightly. I currently get a visible change.
I can imagine that that scaling should be done within an animation block and them just run the rotation animation as before, the issue would be then that the rotation would stop while it scales up.
I need it to be seamless. e.g. this code block does not cause a smooth scaling, even though it uses UIViewAnimationOptionBeginFromCurrentState
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut //| UIViewAnimationOptionRepeat
animations:(void (^)(void)) ^{
imageViewToScale.transform = CGAffineTransformMakeScale(1.2, 1.2);
}
completion:^(BOOL finished){
//imageViewToScale.transform=CGAffineTransformIdentity;
}];
回答1:
To be honest if your going to have continuous animations on your views that will alter there states at run time UIView animations isn't he best approach and might cause jitter whilst the completion handler is called over and over e.t.c.
However is you want to do 2 animations in the block you can either set the scale and the rotation in the same block and they will happend simultaneously. Or you could call a function that starts the block and on completion calls it again to see if there are any new animations for that view. When there are none, the completion block just stops, sort of using them recursively, though this isn't the approach i wouldn't recommend if you are doing a lot of animations on a lot of views continuouly.
In OpenGLES you use NSTimer to run continuous animation that would handle the updating of all animations in your app. If you go this route its a lot more hard work and you need to implement the easing/quadratic curve functions for smooth animation yourself. However if you extend the clases you could set states for each image and then when the timer fires you could update its transformation based one the states you have given it. So when it has rotated a certain amount of degrees/radians then you could set it to scale. Now to keep animation smoothly you will need to use NSTimerIntervals to make sure you multiply the distance moved by time elapsed in order to get smooth animation. Personally this is the route i use for things that might be moving on screen constantly but might be over kill if you need to only move things twice and then be done.
EDIT: The code for doing the second step as you asked!
So you need to declare a NSTimer that wil poll your animation steps and an NSTimeInterval so that you update your animation each step only by the amount of time that has passed.
NSTimer *animationTimer;
NSTimeInterval animationInterval;
NSTimeInterval lastUpdateTime;
float currentRotation;
float current scale;
Thirdly you need to set up an NSTimer to fire off updating of your views:
- (void)startAnimation
{
animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView:) userInfo:nil repeats:YES];
}
- (void)stopAnimation
{
[animationTimer invalidate];
animationTimer = nil;
}
Then you need to kick the thing off when your view starts or when you want to start anmation something like this works
- (void)setAnimationInterval:(NSTimeInterval)interval
{
animationInterval = interval;
if(animationTimer)
{
[self stopAnimation];
[self startAnimation];
}
}
Then In your drawView: Method you need to update your transforms based on time elapsed between each fire of the timer so that the animation is smooth and constant over time. Essentially a linear transform at this point.
- (void)drawView:(id)sender
{
if(lastUpdateTime == -1)
{
lastUpdateTime = [NSDate timeIntervalSinceReferenceDate];
}
NSTimeInterval timeSinceLastUpdate = [NSDate timeIntervalSinceReferenceDate] - lastUpdateTime;
currentRotation = someArbitrarySCALEValue * timeSinceLastUpdate;
currentScale = someArbitraryROTATIONValue * timeSinceLastUpdate;
CGAffineTransform scaleTrans = CGAffineTransformMakeScale(currentScale,currentScale);
CGAffineTransform rotateTrans = CGAffineTransformMakeRotation(currentRotation * M_PI / 180);
imageViewToScale.transform = CGAffineTransformConcat(scaleTrans, rotateTrans);
lastUpdateTime = [NSDate timeIntervalSinceReferenceDate];
}
Note this will not add easing to your animations nor will it at physics to the stopping you will need to play around with that. Also you may need to make sure that when the rotation goes over 360 you reset it to 0 and that you convert between degrees and radians respectively.
Look into using physics for things like bounces, and friction to make things slow nicely.
Look into quadratic graphs for easing to make things move smoothly over time, quadratic interpolation essentially.
来源:https://stackoverflow.com/questions/16787798/updating-running-animations-smoothly