Hello, I have another treat to share!
Juce has grown to become a wonderfully elegant library, capable of (among many other things) extremely attractive user interfaces. However, there is one aspect that has been somewhat overlooked, which is now becoming increasingly apparent; in these times of iOS gadgets and UI reinvention, almost everything is animated. Juce currently provides only minimal in-built support for animation; there is the ComponentAnimator, which can fade or change the bounds of a Component, but anything else you have to do yourself. As such, it’s been something of a mission of mine to create a framework upon which more advanced animation features can be built.
And so, I am posting this, the first working stage of this framework. It’s a powerful set of classes, but this is the first public iteration, providing the foundation; there are some examples of ways it could be used, but by no means a complete picture of the system’s scope. As a result, the demo app is utter crap, but the code shows tantalising glimpse of what can be…
This archive contains a jucer project, consisting of the core animation framework files and an utterly lame example app.
[size=150]What there is, what it does, and how it works…[/size]
Here’s a basic overview, in roughly bottom-to-top order (i.e. Low-level core -> higher level interface), illustrating how the system’s layers are built up:
TimingNode provides the ability to create a hierarchy of temporal references, each with their own window of activity and transformation (and each conveniently shifted such that t=0 is directly meaningful to anything using it). When the time changes for one, all children are automatically updated, allowing a root node to act as a clock to drive many systems.
An Animation is a reference counted object (with its own TimingNode), defining some activity which is to be performed over a certain span of time. It has the ability to notify listeners should its activity actually change any data when it updates. This class uses a LoopTransform, which manipulates its own TimingNode’s local time to provide simply looping functionality (e.g. Duration, number of loops, ping-pong, etc). In the animation’s virtual ‘update’ function, the time provided is the transformed looping time, so any behaviour can simply refer to that.
An Animator (also with a TimingNode) can be used to play Animations. Whenever an animation has expired (its running time has passed through its window of activity), it is automatically stopped and removed. This class is abstract, with virtual start/stop functions; when the first animation is added, it will ‘start’, when the last animation is removed, it will ‘stop’. For example, the TimerBasedAnimator will start/stop a timer, ensuring that nothing happens unless animations are present.
An AnimatedObject is a special type of Animator, designed to play animations relevant to some complex structure with many animatable properties. This defines the Animator start/stop behaviour to connect to (or disconnect from) a designated source Animator. Also, it listens to any Animations it may be playing on itself; whenever time has advanced, if any of its active animations have caused changes, it provides an ‘applyChanges’ callback, allowing you to finalise them in complex situations (e.g. To reconstruct an AffineTransform from separated properties such as rotation, scale, etc.).
BasicAnimation is a simplified base for animations that only care about a normalised 0-1 progress value. This is ideal for simple animations where all you want to do is interpolate between two values.
BasicValueAnimation extends this by taking start/end values, and a target Value object to control.
ValueTreeAnimator is a type of AnimatedObject, designed to animate properties in a ValueTree. It has an interface to retrieve a Value for a property by some locator String; the default implementation simply assumes it is a root property identifier, but you can easily extend it to parse it as, for example, a path to some child node’s property. It also has a stupidly simple interface for animating values; simply call ‘animateValueTo’ using a locator string, a target value and a duration, and it will do everything for you (i.e. Locate the specified Value, create a BasicValueAnimation starting with the current value, and start it playing). Also, because of the way Animators are designed, they will automatically start/stop/connect/disconnect/etc… when needed, behind the scenes, so you don’t have to worry about it.
That’s as far as it has come as of today, but I’m by no means finished - I still have a lot to do; for example, I’m going to add time shaping functionality to BasicAnimation (allowing you to provide a transformation to the 0-1 progress, to easily add things like ease in/out without having to change the actual interpolation). Also, I’d like to put together a ready-made interface for trivially animating all aspects of any Components; as far as I’m concerned, if you have to put any real effort into making your Components animate smoothly, there is something missing. That’s not to discredit Jules’ work though! He’s busy doing far more technically important things, and doing it all like a powerhouse! All I mean is that there is a hole in the coder-side interface of the UI handling side of things, and I want to see it filled.
As usual, this is all purely for selfish reasons, because I want it to be easy for me - it’s just convenient for you lot that I’m lazy enough to feel the need to do it myself
Please feel free to mess around with it all, and let me know what you think.
ADDITIONAL IMPORTANT NOTE ABOUT THE DEMO APP:
Seriously, the actual demo is almost not worth running - all it does is resize a button when you click it. It’s the most basic thing I could be arsed putting together to show how these classes could be used. What is interesting (and in fact the entire purpose of this whole exercise) is the code-side interface possibilities for triggering these (or vastly more exciting) animations. Considering these animations can be easily made to control anything, there is crazy potential, and it should be quite straightforward to build upon all this to make any animations utterly trivial to implement and perform.