1

I'm interested in doing a jiggle like animation for a view, similar to what is described in

ios-icon-jiggle-algorithm and error-in-button-jiggle-algorithm

However, these solutions implement time-invariant animations, meaning that the animation sequence is fixed before the animation starts, and exactly the same animation is performed over and over again. In these cases the rotation angle is pre-calculated.

What I want to do is time-variant animation, where by the animation changes with time. In terms of the previous examples I would like the rotation angle to vary according to some time based function.

To give a real life analogy, imagine that I am animating a block of jelly. At the start of the animation I whack the jelly once and it starts shaking, then slowly over time the size of the shakes decrease, until it is not shaking at all.

From my understanding I can't inject a time varying value into the animation block, and the only course of action I think is possible is chaining together strings of fixed animations as per ios-multiple-animation-blocks. With 3 or 4 blocks of decreasing animation values strung together I should get an effect that might be acceptable.

So if there a way of doing what I want with UIView Animations? Or should I be following another approach?

[Edit]

To be a little clearer about what I mean by time-variant, I want to be able to specify the value of the animated property as a function time, without having to precompute the animated property a priori. And to do so in a way that (possibly) allows me to modify the function on the fly. As a concrete example I might want a function f(t) such that:

For t<0 f(t) = 0
For t>0 and t<1 f(t) = 1-t
For t>1 f(t)= 0

Actually a better representation of a f(t) would be something like:

f(t) = A(t)sin(t)

[Edit #2]

After some consideration I've decided that while ideally being able to specify a time varying view animation is the effect I would like to do, pragmatically when it is applied in the App the user won't likely notice my programing greatness. So I am just going to fake it and use key frame animation that is pre-calculated and triggered multiple times.

Community
  • 1
  • 1
Peter M
  • 7,309
  • 3
  • 50
  • 91

1 Answers1

0

Sorry, you can't do that with UIView animations without chaining multiple of them together by triggering the next in the completion block and you really shouldn't do that.

But don't worry, what you have to do isn't that hard.

Core Animation supports key-frame animations of a property where you can specify an array of values that the property should animate between. You could also specify a path where the property will read its values from.

If you specify an array of values you have fine grained control over the time between the values and how the interpolation (calculation between the specified values) are done.

You create a new animation like this

CAKeyframeAnimation *myJiggleAnimation = [CAKeyframeAnimation animationWithKeyPath:nameOfPropertyBeingAnimated];
// example key paths could be @"position" or @"transform"
[myJiggleAnimation setValues:[NSArray arrayWithValues:/* your values here */]];

Since you are adding object to an NSArray they will have to be contained in objects. For numbers this means using NSNumbers. For this like points, rectangles or transforms there is a class called NSValue that can wrap these, like this

[NSValue valueWithCGPoint:myPoint]; 
[NSValue valueWithCGSize:mySize];
[NSValue valueWithCGRect:myRect]; 
[NSValue valueWithCATransform3D:myTransform]; // 3D transform
[NSValue valueWithCGAffineTransform:myAffineTransform]; // 2D transform 

Then to run the animation you add it to the layer of the view that should animate, like this

[[myView layer] addAnimation:myJiggleAnimation forKey:@"jiggle"];
// The key is used so that you can reference the animation if you have to

Note that at the end of the animation the value of the animated property will not have changed so the view may seem to jump back to it's original state. This is the expected behavior. To have it end at another value, simply set the property to its end value after adding the animation to the layer.


Note: Since it's Core Animation you will have to import QuartzCore.framework into your project and include <QuartzCore/QuartzCore.h> into your code.

David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • I know of keyframe animation, but this still seems to lead me down the path of having to precompute the animation values prior to kicking off the animation. Yes I can have better control how the interpolation occurs, but it still seems to be interpolation of fixed values and not time-varying values. To use key-frame animation as an example, I want to specify values as values = f(t), which are computer at each "animation cycle" at time t, and where f(t) itself varies with time. – Peter M Jul 17 '12 at 21:41
  • None of the built in animations support that (as far as I know). Maybe you could subclass CAPropertyAnimation and do it yourself (or maybe subclass CAValueFunction (the class that does the interpolation) and use that as the interpolation on a basic animation. I haven't tried any of these things though so I'm not sure if they would be really hard to do or if it would even work. – David Rönnqvist Jul 18 '12 at 11:57
  • Yep .. I think I am SOL with the standard animations, and subclassing those standard classes seems a little too much for what I want to do. I could achieve what I want with an OpenGL solution but that is going way too far for this App. – Peter M Jul 18 '12 at 12:41