0

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];
Apollo
  • 8,874
  • 32
  • 104
  • 192

3 Answers3

2

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: enter image description here

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?

Community
  • 1
  • 1
SomeGuy
  • 9,670
  • 3
  • 32
  • 35
0

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)!

pbasdf
  • 21,386
  • 4
  • 43
  • 75
0

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.

Duncan C
  • 128,072
  • 22
  • 173
  • 272