Reputation: 9064
I'm trying to make a circle expand quickly for the first 1-2 seconds and then decrease in speed by which it grows. I thought that a logarithmic scale would be best suited for this, but I don't know how to create one. I'm using the following code to animate the circle:
// Create a view with a corner radius as the circle
self.circle = [[UIView alloc] initWithFrame:CGRectMake(currentPos.x, currentPos.y, 10, 10)];
[self.circle.layer setCornerRadius:self.circle.frame.size.width / 2];
[self.circle setBackgroundColor:[UIColor clearColor]];
self.circle.layer.borderColor = [UIColor redColor].CGColor;
self.circle.layer.borderWidth = .5f;
UIPanGestureRecognizer *move = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[self.circle addGestureRecognizer:move];
[self.view addSubview:self.circle];
[UIView animateWithDuration:5 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^(void){
// Animate it to double the size
const CGFloat scale = 2;
[self.circle setTransform:CGAffineTransformMakeScale(scale, scale)];
} completion:nil];
Upvotes: 0
Views: 830
Reputation: 131491
I don't think view animations allow any curves other than linear and the "ease" style animations.
As I recall, Core Animation allows you to define a custom timing function using a cubic bezier curve. You should be able to create a bezier curve that approximates a log curve.
See the docs on CAMediaTimingFunction for info on creating custom timing functions for Core Animation methods.
Be warned, though, that Core Animation is a pretty involved subject. Core Animation methods are not nearly as easy to use as UIView animations like the code you posted.
Upvotes: 0
Reputation: 21536
I would use animateKeyframesWithDuration:
. This lets you set the scale at different points during the animation (so it can be non-linear). You do this with separate 'addKeyFrameWithRelativeStartTime:` calls. For example:
double total_duration = 5;
[UIView animateKeyframesWithDuration:total_duration delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^(void){
const CGFloat final_scale = 2;
double acceleration = 1000; // the bigger this number, the bigger the initial acceleration
double multiplier = (final_scale - 1) / (logf(1+ (1/acceleration)) - logf(1/acceleration));
double addon = 1 - multiplier * logf(1/acceleration);
double segments = 20;
for (int segment = 0 ; segment < segments ; segment++) {
[UIView addKeyframeWithRelativeStartTime:(segment/segments) relativeDuration:(1.0/segments) animations:^(void){
double scale = multiplier * logf(segment/segments + (1/acceleration)) + addon;
self.circle.transform = CGAffineTransformMakeScale(scale,scale);
}];
}
} completion:nil];
achieves roughly what you want (though forgive the messy maths, it can probably be simplified)!
Upvotes: 0
Reputation: 9700
The easiest way is to use the built in animation options, you can set the animation ease (UIViewAnimationOptionCurveEaseOut)
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction animations:^(void){
// Animate it to double the size
const CGFloat scale = 2;
[self.circle setTransform:CGAffineTransformMakeScale(scale, scale)];
} completion:nil];
These are the built in ease types:
If you wanted something different to this then you'd need to do it yourself I believe.
Thanks to this post for the ease images How to create custom easing function with Core Animation?
Upvotes: 2