Dynamic Animation Library
This tutorial describes the NUI animation framework, covering the following subjects:
Overview
Animation creation
Animatable properties
Animating properties
Controlling animation
Animation Types
Alpha Functions
Events
Animation multithreading
Working example
Animation class methods
Animation class properties
Animation enables you to create animated effects, by changing object properties such as position, for a specified duration.
NUI provides a rich and easy to use animation framework which allows the creation of visually rich applications.
The Animation
class can be used to animate the animatable properties of any number of objects, typically View’s.
NUI animations occur in a dedicated thread. This allows animations to run smoothly, regardless of the time taken to process the input, events, and other factors in the application code.
This image shows the Animation classes in the NUI class hierarchy. The Animatable
class contains ‘property’
methods such as GetProperty
and IsPropertyAnimatable
. The Animation
class contains animation methods
such as AnimateBy
and AnimateTo
.
Here an animation object is created, and the duration of the animation will be 2 seconds:
_animation = new Animation( 2000 );
alternatively,
_animation = new Animation
{
Duration = 2000;
};
Properties can be ‘animatable’. Examples af animatable View
properties are - Position, Orientation, Scale, Color etc.
For ‘standard’ controls, the animatable state of a property can be queried (via IsPropertyAnimatable
), but not changed.
The animatable state can be set in the derived classes of custom view controls.
See also Properties in custom views, and Creating Transitions which describes animatable ‘Scriptable Properties’.
There are two distinct ways in which properties can be animated within DALi:
Here is an example:
(Assume view1
and view2
are at position 10.0f, 10.0f, 0.0f at the start of the animation).
// Animate the position of view1 TO 10.0f, 50.0f, 0.0f
animation.AnimateTo( view1, "Position", Vector3(10.0f, 50.0f, 0.0f) ); // End Position: 10.0f, 50.0f, 0.0f
// Animate the position of view2 BY 10.0f, 50.0f, 0.0f
animation.AnimateBy( view2, "Position", Vector3(10.0f, 50.0f, 0.0f) ); // End Position: 20.0f, 60.0f, 0.0f
Another example taken from the working example in this tutorial:
_animation.AnimateTo(_text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine));
_animation.AnimateTo(_text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine));
_animation.AnimateBy(_text, "ScaleX", 3, 1000, 1500);
_animation.AnimateBy(_text, "ScaleY", 4.0f, 1500, 2000);
Properties can also be passed to an animation method via property
class instantiation:
_animation.AnimateTo(new Property(_text, View.Property.ORIENTATION), new Property.Value(new Rotation(new Radian(new Degree(180.0f)), ...
See Animate methods for explanation of parameters.
When an animation is created, it can be played:
animation.Play();
Stop and Pause are also supported.
animation.Stop();
animation.Pause();
To loop the animation to play multiple times:
animation.SetLooping(true);
By default, when an animation ends, the properties that it was animating are ‘baked’. However, the property changes can be discarded when the animation ends (or is stopped):
animation.EndAction = Animations.EndActions.Discard;
Applications can be notified when the animation finishes:
_animation.Finished += AnimationFinished;
public void AnimationFinished(object sender, EventArgs e)
{
Tizen.Log.Debug("NUI", "AnimationFinished()");
...
...
}
Applications can be notified when the animation has reached a given progress percentage:
_animation.ProgressNotification = 0.5; // trigger 'progress reached' event at 50% of animation time
...
...
_animation.ProgressReached += progressReached;
Alpha functions are used in animations to specify the rate of change of the animation parameter over time. This allows
the animation to be accelerated, decelerated, repeated or bounced. The built in supported functions can be viewed
in the AlphaFunction
class.
It is possible to specify a different alpha function for each animator in an Animation object:
animation.AnimateTo(view1, "Position", Vector3(10.0f, 50.0f, 0.0f), new AlphaFunction.BuiltinFunctions.Linear);
The AnimateTo
parameters are described in Animate methods
The ‘built in’ alpha functions are :
public enum BuiltinFunction {
Default,
Linear,
Reverse,
EaseInSquare,
EaseOutSquare,
EaseIn,
EaseOut,
EaseInOut,
EaseInSine,
EaseOutSine,
EaseInOutSine,
Bounce,
Sin,
EaseOutBack,
Count
}
The animation working example includes the use of a built in alpha function.
You can also create your own alpha function, by setting the default alphafunction:
float alphafunc(float progress)
{
if ( (progress > 0.2f) && (progress < 0.7f) )
{
return progress + 0.8f;
}
return progress;
}
AlphaFunction af(alphafunc);
animation.SetDefaultAlphaFunction(af);
or by using delegates:
private UserAlphaFunctionDelegate _user_alpha_func;
...
...
// Declare user alpha function delegate
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate float UserAlphaFunctionDelegate(float progress);
...
...
_user_alpha_func = new UserAlphaFunctionDelegate(alphafunc);
...
...
_animation.AnimateTo(_view2, "Position", new Vector3(150.0f, 150.0f, 0.0f), 5000, 10000, new AlphaFunction(_user_alpha_func));
NUI supports both key-frame and path animation.
NUI provides support for animating between several different values, i.e. key-frames. A key frame takes a progress value between 0.0f and 1.0f (0 and 100% respectively) and portrays the value of the property when the animation has progressed that much.
You can create several key frames:
KeyFrames keyFrames = new KeyFrames();
keyFrames.Add( 0.0f, new Vector3( 10.0f, 10.0f, 10.0f ) );
keyFrames.Add( 0.7f, new Vector3( 200.0f, 200.0f, 200.0f ) );
keyFrames.Add( 1.0f, new Vector3( 100.0f, 100.0f, 100.0f ) );
And then add them to your animation:
animation.AnimateBetween( view1, "Position", keyFrames);
When the animation runs, NUI animates the position of view1
between the specified key frames.
view1
will animate from (10.0f, 10.0f, 10.0f) to (200.0f, 200.0f, 200.0f) by 70% of the animation time,
and then spend the remaining time animating back to (100.0f, 100.0f, 100.0f).
The advantage of specifying a key frame at 0% is that regardless of where view1
is, it will start from position (10.0f, 10.0f, 10.0f).
If AnimateTo
was used, then the start position would have been view1's
current position.
Here is a more comprehensive example of ‘Key frame’ use, taken from FocusEffect.cs
:
focusData.ImageItem.Size = new Size(100.0f, 100.0f, 0.0f);
parentItem.Add(focusData.ImageItem);
Size targetSize = focusData.TargetSize;
Size initSize = focusData.InitSize;
...
...
KeyFrames keyFrames = new KeyFrames();
keyFrames.Add(0.0f, initSize);
keyFrames.Add(focusData.KeyFrameStart, initSize);
keyFrames.Add(focusData.KeyFrameEnd, targetSize);
// for halo add an extra keyframe to shrink it ( in 20% of time after it has finished)
if (focusData.Name == "halo")
{
keyFrames.Add(focusData.KeyFrameEnd + 0.2f, initSize);
}
_animation.AnimateBetween(focusData.ImageItem, "Size", keyFrames, Animation.Interpolation.Linear, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
A Path
can be used to animate the position and orientation of views.
The logo will travel to the black points on the diagram. The red points are the control points which express the curvature of the path on the black points.
Here is the code sample:
Animation animation = new Animation();
...
...
Path path = new Path();
path.AddPoint( new Position( 50.0f, 10.0f, 0.0f ));
path.AddPoint( new Position( 90.0f, 50.0f, 0.0f ));
path.AddPoint( new Position( 10.0f, 90.0f, 0.0f ));
The control points can be added manually using AddControlPoint
, or Path
can auto-generate them for you:
path.GenerateControlPoints(0.25f);
Here 0.25f represents the curvature of the path you require. The generated control points result in a smooth join between the splines of each segment.
To animate view1
along this path:
animation.AnimatePath( view1, path, new Position(0.0f, 0.0f, 0.0f) );
The third parameter is the forward vector (in local space coordinate system) that will be oriented with the path’s tangent direction.
Another example:
// black points
Position position0 = new Position(200.0f, 200.0f, 0.0f);
Position position1 = new Position(300.0f, 300.0f, 0.0f);
Position position2 = new Position(400.0f, 400.0f, 0.0f);
Path path = new Path();
path.AddPoint(position0);
path.AddPoint(position1);
path.AddPoint(position2);
// Control points for first segment
path.AddControlPoint(new Vector3(39.0f, 90.0f, 0.0f));
path.AddControlPoint(new Vector3(56.0f, 119.0f, 0.0f));
// Control points for second segment
path.AddControlPoint(new Vector3(78.0f, 120.0f, 0.0f));
path.AddControlPoint(new Vector3(93.0f, 104.0f, 0.0f));
Animation animation = new Animation();
animation.AnimatePath(view, path, Vector3.XAxis, 0, 5000, new AlphaFunction(AlphaFunction.BuiltinFunctions.Linear)); // X Axis
animation.Play();
Note: AnimatePath
invokes Animate
.
NUI animations and rendering occur in a dedicated rendering thread. This allows animations to run smoothly, regardless of the time taken to process events in application code.
Internally NUI contains a scene-graph, which mirrors the views hierarchy. The scene-graph objects perform the actual animation and rendering, whilst views provide thread-safe access.
An example view hierarchy is shown below, in which one of the views is being animated. The objects in green are created by the application code, whilst the private objects in blue are used in the dedicated rendering thread.
When a property is animatable, it can only be modified in the rendering thread. The value returned from a ‘get’ property, is the value used when the previous frame was rendered.
For example pos = view.Position
returns the position at which the view was last rendered. Since setting a position i.e. view.Position = pos
is asynchronous, pos = view.Position
won’t immediately return the same value.
// Whilst handling an event...
View view = new View();
Window.Instance.Add(view); // initial position is 0,0,0
view.Position = new Position(10,10,10);
Position current = view.Position;
Console.WriteLine("Current position: " + current.X + ", " + current.Y + ", " + current.Z);
Console.WriteLine("...");
// Whilst handling another event...
current = view.Position;
Console.WriteLine("Current position: " + current.X + ", " + current.Y + ", " + current.Z);
The example code above would likely output:
Current position: 0,0,0
...
Current position: 10,10,10
When a property is being animated, the Animation will override any values set.
The order of execution in the render thread is:
1. Process message => SetPosition
2. Apply animation => SetPosition
3. Render frame
A simple text animation example has been created to illustrate some of the principles outlined in this guide, including the use of the
AnimateBy
, AnimateTo
methods and an alphafunction.
Read the instructions in Building NUI source code of the ubuntu setup guide, which includes an explanation of where to place tutorial files. (‘nuirun’ folder).
cp animation-hello-world.cs ~/DALiNUI/nuirun/tutorials
The Animation
class provides a series of overloaded methods for animation of properties, including:
public void AnimateBy(View target, string property, object relativeValue, AlphaFunction alphaFunction = null)
public void AnimateBy(View target, string property, object relativeValue, int startTime, int endTime, AlphaFunction alphaFunction = null)
Parameter | Description |
---|---|
target | The target object to animate |
property | The target property to animate, can be enum or string |
relativeValue | The property value will change by this amount |
alphaFunction | The alpha function to apply |
startTime | Start time of animation |
endTime | End time of animation |
public void AnimateTo(View target, string property, object destinationValue, AlphaFunction alphaFunction = null)
public void AnimateTo(View target, string property, object destinationValue, int startTime, int endTime, AlphaFunction alphaFunction = null)
public void AnimateBetween(View target, string property, KeyFrames keyFrames, Interpolation interpolation = Interpolation.Linear, AlphaFunction alphaFunction = null)
public void AnimateBetween(View target, string property, KeyFrames keyFrames)
Parameter | Description |
---|---|
keyFrames | The set of time/value pairs between which to animate |
interpolation | The method used to interpolate between values |
public void AnimatePath(View view, Path path, Vector3 forward, AlphaFunction alphaFunction = null)
Parameter | Description |
---|---|
path | Defines position and orientation |
forward | The vector (in local space coordinate system) that will be oriented with the path’s tangent direction |
Animation
class properties include:
Property | Type | Description |
---|---|---|
Duration | int | Gets/Sets the duration in milli seconds of the animation. |
DefaultAlphaFunction | AlphaFunction | Gets/Sets the default alpha function for the animation. |
State | States | Queries the ‘state’ of the animation. (Stopped, Playing or Paused) |
LoopCount | int | Set : Enables looping for ‘count’ repeats. A zero is the same as Looping = true; i.e. repeat forever |
Get : Gets the loop count. | ||
Looping | bool | Gets/Sets the status of whether the animation will loop. (resets the loop count). The loop count is initially 1 for play once. |
EndAction | EndActions | Gets/Sets the end action of the animation. This action is performed when the animation ends, or if it is stopped |
CurrentLoop | int | Gets the current loop count |
DisconnectAction | EndAction | Gets/Sets the disconnect action. |
CurrentProgress | float | Gets/Sets the progress of the animation. |
SpeedFactor | float | Gets/Sets specifies a speed factor for the animation. |
PlayRange | RelativeVector2 | Animation will play between the values specified. Both values(range.x and range.y ) should be between 0 and 1 |
ProgressNotification | float | Gets/Sets the Progress notification marker which triggers the ProgressReached Event, should be between 0 and 1 |