Elementary Animations: Applying Transition Effects to an Evas Object
This tutorial demonstrates how you can use Elm Transit to create animated transitions effects, such as rotation, wiping, zooming, resizing, and fading, to an Evas_Object.
Warm-up
Become familiar with the Ecore, Elementary, and Evas API basics by learning about:
-
Setting Up the Application
Prepare the application for use.
-
Creating a Rotation Effect
Create a rotation effect in your application.
-
Creating a Zoom Effect
Create a zoom effect in your application.
-
Creating a Flip Effect
Create a flip effect in your application.
-
Creating a Blend Transition
Create a blend transition in your application.
-
Creating a Fade Effect
Create a fade effect in your application.
-
Creating a Flip on y Axis
Create a flip on y axis in your application.
-
Creating a Wipe Effect
Create a wipe effect in your application.
-
Implementing Elementary Transit Effects
Demonstrates how you can implement a variety of EFL animation effects.
Setting Up the Application
First create a basic application like explained in the Basic Tutorial.
When the application is ready, create Evas objects and animate them. In this example, one single object is animated with different type of animations.
Create the structure of our application represented by a struct named appdata
typedef struct appdata { Evas_Object *win; Evas_Object *label; Evas_Object *button; Evas_Object *buttonbck; Evas_Object *hbox; Evas_Object *left_vbox; Evas_Object *center_vbox; Evas_Object *right_vbox; float rt_angle, zto, zfrom; } appdata_s;
This structure holds the main UI components of the application:
- win: the main window
- label: the title label
- button: a button object, the target of the animations
- buttonbck: a button representing the back of the target button
- left_vbox: a vertical box to place the first buttons column
- center_vbox: a vertical box to store the second buttons column
- right_vbox: a vertical box to store the last buttons column
- hbox: a horizontal box to store the vertical boxes
- rt_angle, zto, zfrom: these variables are used to store values for animations
Place the UI components on the application's canvas. To make things easier, the UI component creation is split into two functions.
The first function creates UI components on the main window, and the second in the boxes.
create_base_gui(appdata_s *ad) { ad->rt_angle = 360.0; ad->zfrom = 1.0; ad->zto = 2.0; // Window ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE); elm_win_autodel_set(ad->win, EINA_TRUE); if (elm_win_wm_rotation_supported_get(ad->win)) { int rots[4] = { 0, 90, 180, 270 }; elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4); } evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL); // Label ad->label = elm_label_add(ad->win); elm_object_text_set(ad->label, "Effects Tutorial"); evas_object_size_hint_weight_set(ad->label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(ad->win, ad->label); evas_object_show(ad->label); // Show the window after the base GUI is set up evas_object_show(ad->win); ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keydown_cb, ad); // Creation a button in the app window ad->button = elm_button_add(ad->win); // Moving the button to x=50 y=100 evas_object_move(ad->button, 50, 100); // Resizing the button 100x50 evas_object_resize(ad->button, 200, 50); // Showing the button evas_object_show(ad->button); // Creation a back button in the app window ad->buttonbck = elm_button_add(ad->win); elm_object_text_set(ad->buttonbck, "Button back"); evas_object_move(ad->buttonbck, 50, 100); evas_object_resize(ad->buttonbck, 200, 50); _create_btn_box(ad); } // End of create_base_gui
This function takes appdata_s *ad as its only parameter. This function is called by the creation callback app_create of the Tizen application (event_callback.create = app_create;) in the main function of the application.
Set up the needed values like the rotation angle, the original zoom value (zfrom), and the destination zoom value (zto).
ad->rt_angle = 360.0; ad->zfrom = 1.0; ad->zto = 2.0;
Create the main window with a title and add the delete callback:
// Window ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE); elm_win_autodel_set(ad->win, EINA_TRUE); if (elm_win_wm_rotation_supported_get(ad->win)) { int rots[4] = { 0, 90, 180, 270 }; elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4); } evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL); // Label ad->label = elm_label_add(ad->win); elm_object_text_set(ad->label, "Effects Tutorial"); evas_object_size_hint_weight_set(ad->label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(ad->win, ad->label); evas_object_show(ad->label); // Show the window after the base GUI is set up evas_object_show(ad->win); ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keydown_cb, ad);
Next create the animation target button and the back button. Call the button box creation function with the application data as its parameter.
_create_btn_box(ad);
Add a set of buttons to this box that starts animations on the animation target.
Create the structure of the buttons box with three columns (vertical boxes) and one horizontal for the main container.
// Creation of the main container box ad->hbox = elm_box_add(ad->win); elm_box_horizontal_set(ad->hbox, EINA_TRUE); elm_box_homogeneous_set(ad->hbox, EINA_TRUE); evas_object_move(ad->hbox, 10, 500); evas_object_show(ad->hbox); // Creation of the first column ad->left_vbox = elm_box_add(ad->hbox); elm_box_horizontal_set(ad->left_vbox, EINA_FALSE); elm_box_homogeneous_set(ad->left_vbox, EINA_TRUE); evas_object_show(ad->left_vbox); elm_box_pack_start(ad->hbox, ad->left_vbox); // Creation of the second column ad->center_vbox = elm_box_add(ad->hbox); elm_box_horizontal_set(ad->center_vbox, EINA_FALSE); elm_box_homogeneous_set(ad->center_vbox, EINA_TRUE); evas_object_show(ad->center_vbox); elm_box_pack_end(ad->hbox, ad->center_vbox); // Creation of the last column ad->right_vbox = elm_box_add(ad->hbox); elm_box_horizontal_set(ad->right_vbox, EINA_FALSE); elm_box_homogeneous_set(ad->right_vbox, EINA_TRUE); evas_object_show(ad->right_vbox); elm_box_pack_end(ad->hbox, ad->right_vbox);
Then create the first action button for the resize effect.
// Button creation btn_resize = elm_button_add(ad->win); // Setting the button text elm_object_text_set(btn_resize, "Resize"); // Setting the hint weight policy evas_object_size_hint_weight_set(btn_resize, EVAS_HINT_FILL, EVAS_HINT_FILL); // Showing the button evas_object_show(btn_resize); // Setting the "clicked" callback evas_object_smart_callback_add(btn_resize, "clicked", _btn_resize_cb, ad); // Adding the button to the first column elm_box_pack_end(ad->left_vbox, btn_resize);
evas_object_smart_callback_add defines the callback function that is to be called when the button is clicked. In this example, set a _btn_resize_cb function and pass the application data ad to this callback function.
The callback by itself only sets a new text for the animation target button, and calls a function which will actually animate the button.
static void _btn_resize_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Starting the rotation effect 360 degrees // evas_object_resize(ad->button, 100, 50); elm_object_text_set(ad->button, "Resize"); _resize_effect(ad->button); }
This function is an evas_object_smart_callback and thus needs to have its specific prototype: it does not return anything and receives three parameters:
- data: data to be passed
- btn: the object the callback is being called about
- ev: the actual event, seldom used
In this case, use data to pass the application data to the callback. However, the parameter's type is void * and not appdata_s *. Initialize a variable of the correct type with the pointer.
appdata_s *ad = data;
Then use the application data in the callback function. At this point create the animation directly in the callback function, but it is more straightforward to encapsulate the animation process into a dedicated function. _resize_effect implements the animation code:
static void _resize_effect(Evas_Object *obj) { // Elementary Transition declaration and creation Elm_Transit *trans = elm_transit_add(); // Adding the transition target object elm_transit_object_add(trans, obj); // Setting the resize effect elm_transit_effect_resizing_add(trans, 100, 50, 300, 150); // Setting the transition duration elm_transit_duration_set(trans, 3.0); // Starting the transition elm_transit_go(trans); }
Create an Elm_Transit * object representing the transition.
Elm_Transit *trans = elm_transit_add();
Then add the target object to the transition
elm_transit_object_add(trans, obj);
Add a resizing transition to the object with the origin and destination width and height in pixels.
elm_transit_effect_resizing_add(trans, 100, 50, 300, 150);
100 and 50 are respectively the object's width and height when the effect begins, whereas 300 and 150 are respectively the object's width and height when the effect ends: the object grows from 100×50 to 300×150.
After that set the transition duration with elm_transit_duration_set.
elm_transit_duration_set(trans, 3.0);
The animation lasts three seconds. The duration parameter is a double.
Now start the animation by calling elm_transit_go with the Elm_Transit object.
elm_transit_go(trans);
When the resize button is clicked, the animation target button grows.
All the action buttons are created exactly the same way as the resize button, with a callback and an animation function.
Creating a Rotation Effect
This effect rotates the animation target button with an angle of 360°. This angle is stored in the application data as ad->rt_angle.
Create the button and add it to the center column in the _create_btn_box function.
// The rotation button btn_rotate = elm_button_add(ad->win); elm_object_text_set(btn_rotate, "Rotate"); evas_object_size_hint_weight_set(btn_rotate, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_rotate); evas_object_smart_callback_add(btn_rotate, "clicked", _btn_rotate_cb, ad); elm_box_pack_end(ad->center_vbox, btn_rotate);
In the rotate button callback, call the effect function with the target button as first parameter and the rotation angle as the second one.
static void _btn_rotate_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Setting the button text elm_object_text_set(ad->button, "Rotate"); _rotation_effect(ad->button, ad->rt_angle); }
The animation function rotates the animation target by adding a rotation effect with elm_transit_effect_rotation_add. This function takes three parameters:
- Elm_Transit
- the rotation position at which the effect begins
- the rotation position at which the effect ends
Rotation starts at 0° to finish at 360°. The animation lasts two seconds.
static void _rotation_effect(Evas_Object *obj, float angle) { Elm_Transit *trans = elm_transit_add(); elm_transit_object_add(trans, obj); // Rotates the object from its original angle to given degrees to the right elm_transit_effect_rotation_add(trans, 0.0, angle); elm_transit_duration_set(trans, 2.0); elm_transit_go(trans); }
Creating a Zoom Effect
The zoom effect zooms on the animation target to make it twice bigger. Store the source rate and the destination rate in the application data using ad->zfrom and ad->zto.
Create the button and add it to the center column in the _create_btn_box function.
// The zoom button btn_zoom = elm_button_add(ad->win); elm_object_text_set(btn_zoom, "Zoom"); evas_object_size_hint_weight_set(btn_zoom, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_zoom); evas_object_smart_callback_add(btn_zoom, "clicked", _btn_zoom_cb, ad); elm_box_pack_end(ad->right_vbox, btn_zoom);
Then add a callback function in order to perform the animation.
static void _btn_zoom_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Starting the rotation effect 360 degrees // evas_object_resize(ad->button, 100, 50); elm_object_text_set(ad->button, "Zoom"); _zoom_effect(ad->button, ad->zfrom, ad->zto); }
To create the zoom effect, use elm_transit_effect_zoom_add with the start rate and the destination rate stored in application data (ad->zfrom and ad->zto)
static void _zoom_effect(Evas_Object *obj, float from, float to) { Elm_Transit *trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_effect_zoom_add(trans, from, to); elm_transit_duration_set(trans, 2.0); elm_transit_go(trans); }
Creating a Flip Effect
This effect is applied to a pair of objects, in the order they are added, to the Elm_Transit transition. In this example, add the animation target button and the button called buttonbck which represents the back of the target button.
Create the action button for the flip effect:
// The flip button btn_flip = elm_button_add(ad->win); elm_object_text_set(btn_flip, "Flip x"); evas_object_size_hint_weight_set(btn_flip, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_flip); evas_object_smart_callback_add(btn_flip, "clicked", _btn_flip_cb, ad); elm_box_pack_end(ad->left_vbox, btn_flip);
The corresponding callback to create and start the animation with the two objects (target button and back button) to animate is like follows.
static void _btn_flip_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Setting the button text elm_object_text_set(ad->button, "Flip"); _flip_effect(ad->button, ad->buttonbck); }
Create the function which runs the animation. This flip animation is created using elm_transit_effect_flip_add. The second parameter is the axis of the flip: in this example it is the X axis, so the button flips down to top to show the back button. The last parameter is the flip direction: EINA_TRUE means clockwise.
static void _flip_effect(Evas_Object *obj, Evas_Object *obj2) { Elm_Transit *trans; trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_object_add(trans, obj2); elm_transit_effect_flip_add(trans, ELM_TRANSIT_EFFECT_FLIP_AXIS_X, EINA_TRUE); elm_transit_duration_set(trans, 3.0); elm_transit_go(trans); }
Creating a Blend Transition
The blend effect also works the same way as the flip, but without the axes or direction information. Use the back button here as well. To create the blend effect button:
// The blend button btn_blend = elm_button_add(ad->win); elm_object_text_set(btn_blend, "Blend"); evas_object_size_hint_weight_set(btn_blend, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_blend); evas_object_smart_callback_add(btn_blend, "clicked", _btn_blend_cb, ad); elm_box_pack_end(ad->center_vbox, btn_blend);
The blend transition callback is:
static void _btn_blend_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Setting the button text elm_object_text_set(ad->button, "Blend"); _blend_effect(ad->button, ad->buttonbck); }
Create and start the blend animation. This animation is created by adding it to and Elm_Transit with elm_transit_effect_blend_add. Add two objects, as for the flip.
static void _blend_effect(Evas_Object *obj, Evas_Object *obj2) { Elm_Transit *trans; trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_object_add(trans, obj2); elm_transit_effect_blend_add(trans); elm_transit_duration_set(trans, 3.0); elm_transit_go(trans); }
Creating a Fade Effect
The fade effect works exactly the same way as the blend effect. First create the button:
// The fade button btn_fade = elm_button_add(ad->win); elm_object_text_set(btn_fade, "Fade"); evas_object_size_hint_weight_set(btn_fade, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_fade); evas_object_smart_callback_add(btn_fade, "clicked", _btn_fade_cb, ad); elm_box_pack_end(ad->right_vbox, btn_fade);
Then add the button's callback:
static void _btn_fade_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Setting the button text elm_object_text_set(ad->button, "Fade"); _fade_effect(ad->button, ad->buttonbck); }
The animation function calls elm_transit_effect_fade_add instead of elm_transit_effect_blend_add.
static void _fade_effect(Evas_Object *obj, Evas_Object *obj2) { Elm_Transit *trans; trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_object_add(trans, obj2); elm_transit_effect_fade_add(trans); elm_transit_duration_set(trans, 3.0); elm_transit_go(trans); }
Creating a Flip on y Axis
This is same as the flip transition, but on y axis. To create a flip on y axis:
// The flip y button btn_flip_y = elm_button_add(ad->win); elm_object_text_set(btn_flip_y, "Flip y"); evas_object_size_hint_weight_set(btn_flip_y, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_flip_y); evas_object_smart_callback_add(btn_flip_y, "clicked", _btn_flip_y_cb, ad); elm_box_pack_end(ad->left_vbox, btn_flip_y); static void _btn_flip_y_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Setting the button text elm_object_text_set(ad->button, "Flip 2"); _flip_y_effect(ad->button, ad->buttonbck); } static void _flip_y_effect(Evas_Object *obj, Evas_Object *obj2) { Elm_Transit *trans; trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_object_add(trans, obj2); elm_transit_effect_flip_add(trans, ELM_TRANSIT_EFFECT_FLIP_AXIS_Y, EINA_TRUE); elm_transit_duration_set(trans, 3.0); elm_transit_go(trans); }
Creating a Wipe Effect
The wipe transition is applied on an Evas object considering the wipe type and the direction. Use ELM_TRANSIT_EFFECT_WIPE_TYPE_HIDE to hide the button, and ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT to do it from left to right.
The wipe animation button is as follows:
// The wipe button btn_wipe = elm_button_add(ad->win); elm_object_text_set(btn_wipe, "Wipe"); evas_object_size_hint_weight_set(btn_wipe, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(btn_wipe); evas_object_smart_callback_add(btn_wipe, "clicked", _btn_wipe_cb, ad); elm_box_pack_end(ad->right_vbox, btn_wipe);
The wipe button callback looks like:
static void _btn_wipe_cb(void *data, Evas_Object *btn, void *ev) { appdata_s *ad = data; // Starting the rotation effect 360 degrees // evas_object_resize(ad->button, 100, 50); // Setting the button text elm_object_text_set(ad->button, "Wipe"); _wipe_effect(ad->button); }
The animation function calls elm_transit_effect_wipe_add with ELM_TRANSIT_EFFECT_WIPE_TYPE_HIDE as the second parameter to hide the button and ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT as last parameter to set the direction (left to right).
static void _wipe_effect(Evas_Object *obj) { Elm_Transit *trans; trans = elm_transit_add(); elm_transit_object_add(trans, obj); elm_transit_effect_wipe_add(trans, ELM_TRANSIT_EFFECT_WIPE_TYPE_HIDE, ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT); elm_transit_duration_set(trans, 3.0); elm_transit_go(trans); }