Animations

Overview

XML animations are built on top of Timeline animations.

Timelines are composed of simple animations. For example: "change the ``bg_opa`` of ``my_button_2`` from 0 to 255 in 500 ms."

Each component can define its own timeline animations, which can then be played by the component itself or by any parent component.

Defining Timelines

Timelines can be defined inside <screen>s and <component>s. For <widget>s, timelines are supported only in LVGL's UI Editor, where C code can also be exported from them.

Example:

<component>
   <animations>

       <!-- Show the component and its children -->
       <timeline name="load">
           <animation prop="translate_x" target="self" start="-30" end="0" duration="500"/>
           <animation prop="opa" target="text" start="0" end="255" duration="500" delay="200"/>

           <include_timeline target="icon" timeline="show_up" delay="300"/>
       </timeline>

       <!-- Shake horizontally -->
       <timeline name="shake">
           <animation prop="translate_x" target="self" start="0" end="-30" duration="150"/>
           <animation prop="translate_x" target="self" start="-30" end="30" duration="300" delay="150"/>
           <animation prop="translate_x" target="self" start="30" end="0" duration="150" delay="450"/>
       </timeline>
   </animations>

   <view>
       <lv_button width="200">
           <my_icon name="icon" src="image1"/>
           <lv_label name="text" text="Click me"/>
       </lv_button>
   </view>
</component>

In summary: inside <animations>, you can define <timeline>s, each with a unique name that you can reference later.

Inside a <timeline>, you add <animation>s to describe each step. Supported properties of <animation> are:

  • prop: Style property to animate. All integer style properties are supported (colors are not).

  • selector: Style selector, e.g. knob|pressed. Default: main|default.

  • target: Name of the UI element to animate. self refers to the root element of the component (the <view>).

  • start: Start value (integer only).

  • end: End value (integer only).

  • duration: Duration of the animation in milliseconds.

  • delay: Delay before starting in milliseconds. Default is 0.

  • early_apply: If true, the start value is applied immediately, even during the delay. Default is false.

<include_timeline> also can be used in <timeline>s to "merge" the animations of another timeline. Imagine that in the example above my_icon defines a "show_up" timeline which fades in and scales up the icon. All these are described in the my_icon.xml in an encapsulated way but can be referenced in other timelines.

To include a timeline, the following properties shall be used:

  • target: name of the target UI element whose timeline should be included. self refers to the root element of the component (the <view>).

  • timeline: name of the timeline to include. Shall be defined in the target's XML file.

  • delay: Delay before starting in milliseconds. Default is 0.

Playing Timelines

Timelines can be triggered by events (e.g. click) using <play_timeline_event> as a child of any widget.

Example:

<view>
    <lv_label name="title" text="Hello world!"/>
    <custom_button name="button" y="20">
        <play_timeline_event trigger="clicked" target="button" timeline="bounce"/>
        <lv_label text="Click me"/>
    </custom_button>
</view>

You set a target UI element and select one of its timelines to play. If target="self", the timeline is looked up in the current component/widget/screen (i.e. in the current XML file).

You can also set a delay and reverse="true" when playing a timeline. Under the Hood **********

Understanding how timelines work internally helps in using them effectively.

When an XML file is registered, the contents of the <animations> section are parsed, and the <timeline>'s data is stored as a "blueprint". The descriptors store the targets' names as strings.

When an instance of a component or screen is created, as the last step lv_anim_timelines are created and initialized from the saved "blueprints". If <include_timeline>s are also used, the requested timeline is included in the component's timeline at this point too. As all the children are also created at this point, the saved animation target names are resolved to pointers by using lv_obj_find_by_name.

The created timeline instances and their names are saved in the component's instance.

Since each instance has its own timeline, you can have multiple components (e.g. 10 <list_item>s) and play their load timelines independently with different delays.

When a <play_timeline_event> is added to a UI element, the target and timeline names are saved as strings. It cannot use pointers as the event can reference UI elements that will be created only later in the <view>.

Finally, when the play timeline event is triggered, the selected timeline is retrieved by its name from the target and started according to the other parameters (reverse, delay, etc).