LVGL动画
LVGL动画概述
LVGL里面有好多对象都支持动画效果,比如进度条、滑块、按钮等,但是那些都是对象里面自带的API进行设定的,如果我们想让某个对象拥有动画效果,LVGL也是支持的,只是原子的教程里面没有.
先简单说一下动画的实现原理.
首先,动画由一个双向链表进行管理,该链表除去头尾指针外只记录了动画结构体的大小.
其次,动画的实现其实是LVGL的一个系统内置任务实现.
最后,动画的概念其实和软件定时器高度相似,但是添加了一些额外的属性,总体来说还是比较好理解的.
备注: 如果想加深理解,可以看一下lv_anim.c
文件,内容很少,很容易理解.
动画数据结构
想要使用动画,还需要对动画的数据结构有一定了解.结构如下.
/** Describes an animation*/
typedef struct _lv_anim_t
{
void * var;
lv_anim_exec_xcb_t exec_cb;
lv_anim_path_cb_t path_cb;
lv_anim_ready_cb_t ready_cb;
int32_t start;
int32_t end;
uint16_t time;
int16_t act_time;
uint16_t playback_pause;
uint16_t repeat_pause;
#if LV_USE_USER_DATA
lv_anim_user_data_t user_data;
#endif
uint8_t playback : 1;
uint8_t repeat : 1;
/*Animation system use these - user shouldn't set*/
uint8_t playback_now : 1;
uint32_t has_run : 1;
} lv_anim_t;
下面只说一些对应用有直接影响的参数.
-
var
设定的对象,给哪个对象设定动画效果
-
exec_cb
控制对象属性的函数地址,一般使用
lv_obj_set_x
或者lv_obj_set_y
,使用lv_obj_set_x
的时候,动画左右移动,使用lv_obj_set_y
的时候上下移动.
除了坐标外,还可以设定对象的透明度,颜色等等. -
path_cb
路径算法,比较有意思的一个选项,有如下几个可以选择.
- lv_anim_path_linear 动画效果均速移动
- lv_anim_path_step 没有动画效果,直接跳转到结束位置
- lv_anim_path_ease_in 开头很慢,速度逐渐加速
- lv_anim_path_ease_out 开头很快,速度逐渐减小
- lv_anim_path_ease_in_out 开始速度很慢,在动画中心处存在一个最大速度的时候开始逐渐减速.
- lv_anim_path_overshoot 动画会超过设定值,效果类似于惯性
- lv_anim_path_bounce 动画效果类似于弹性物体落地.
如果有特殊的动画需求可以自行实现动画方法,之后将该函数注册到这个指针即可.
-
ready_cb
动画效果结束后的回调函数,可以根据需求自行填写,lvgl内部其余组件一般是用这个回调做一些收尾工作,比如释放内存.
-
start
动画开始的起点,根据
exec_cb
函数的不同代表不同属性的初始值. -
end
动画开始的终点,根据
exec_cb
函数的不同代表不同属性的结束值. -
time
设定的动画的执行时间,设定5S代表5S秒内从
start
到end
点的时间. -
act_time
动画已经执行的时间
-
playback_pause
动画正放与回放之间的时间间隔
-
repeat_pause
动画重复的时间间隔
-
playback
是否执行动画回放
-
repeat
是否重复播放动画
总结一下,想使用动画,先确定如下几点.
- 给
某个对象
使用动画,使用var
指向该对象. - 动画方向,使用
exec_cb
确认. - 动画范围,就是动画的起点到终点,使用
start
和end
进行确认.如果不选择,默认为0-100
(方向根据exec_cb
确认). - 动画效果,使用
path_cb
进行选择,如果不选择,默认为lv_anim_path_linear
- 动画时长,使用
time
进行调整,如果不修改,默认为500
. - 可选择项,如果想让动画效果滞后一段时间播放,则可以设定
act_time
,需要注意的是,该延时时间仅会生效一次.
上面是一些最基本的属性,还有好多属性可提供选择,举一个简单的例子,让钟表以500ms
的时间从Y轴的0
掉落到Y轴的100
,将该过程称为A
,如果需要回放的话,则打开playback
选项,钟表将会以500ms
的时间从Y轴的100
上升到Y轴0
位置处,将该过程称之为B
.以这个例子解释如下属性.
- 需要打开动画回放功能,打开
playback
即可. - 动画
A
与B
之间的时间间隔以playback_pause
设定. - 动画重复播放,打开
repeat
即可. - 动画重复播放的时间间隔,使用
repeat_pause
设定. - 动画结束后触发
ready_cb
函数,有需求可以设置该指针去做.
备注:
-
playback
和repeat
同时打开后,A
和B
的时间间隔依旧是playback_pause
,AB
和AB
的时间间隔才是repeat_pause
. -
这个
repeat
更像是一个定时器的标志位,打开了就是周期定时器,关闭了就是一个单次定时器.ready_cb
在repeat
打开的时间不会执行. -
act_time
在repeat
打开时仅会在第一次运行动画效果时执行一次.
动画API
上面介绍了一些重要的成员变量,下面简单说一些能用得到的API,还有相当一部分略过,略过的基本都是内联函数,都是对结构体内部成员变量进行赋值的操作.使用时直接赋值即刻.
lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end)
给出指定
speed
,给出动画的start
和end
坐标,返回值是所用时间.speed
单位是px/sec
.
比如a.time = lv_anim_speed_to_time(100,0,100);
,结果是1000ms
.lv_anim_create(lv_anim_t * a)
创建一个动画,使用的时候可以传入局部变量,因为在函数内部会自动申请一个内存块存放动画属性.
lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb)
删除一个动画
lv_anim_count_running()
获取当前系统一共有多少个运行的动画
LVGL如何使用动画
一般场景中,都是触发条件后,执行一次动画,每次在执行动画时,调用如下函数即可.具体参数根据需求自行修改.
static void obj_add_anim()
{
lv_anim_t a;
memset(&a, 0, sizeof(lv_anim_t));
a.var = bg_img; //动画对象
a.exec_cb = lv_obj_set_y; // y轴移动
a.time = lv_anim_speed_to_time(100,0,100); //1S的动画时间
a.start = 10; // 开始坐标
a.end = 120; // 结束坐标
a.act_time = -500; //第一次运行动画时,延时500ms开始
a.path_cb = lv_anim_path_bounce; //模拟弹性物体下落动画
a.ready_cb = ready_call_back; // 自定义的打印函数
a.playback = 0; //不开启动画回放
a.playback_pause = 2000;
a.repeat = 1; //开始重复动画
a.repeat_pause = 200;//每次重复动画时间间隔200ms
lv_anim_create(&a); //必须调用的函数,否则无法使用
}
在LVGL内置的anim
任务中,当动画执行完后,系统会自动释放掉动画管理结构体的内存.所以不用担心内存溢出的问题.