登录发现更多内容
首页
分类
发帖
账号
自动登录
找回密码
密码
登录
立即注册
立即登录
立即注册
其他登录
QQ
微信
首页
Portal
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
产品教程
BBS
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
开发资料
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
样品购买
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
IoT云平台
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
GitHub
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
技术博客
求助问答
Xiuno资源
Xiuno教程
Xiuno插件
Xiuno主题
休闲茶馆
定制主题
搜索
搜索
热搜:
LoRa
ESP8266
安信可
本版
帖子
用户
请
登录
后使用快捷导航
没有账号?
立即注册
每日签到
任务
广播
导读
排行榜
设置
我的收藏
退出
4
1
0
首页
LVGL教程玩法
›
[LVGL]LVGL库入门教程-LVGL动画
返回列表
[LVGL]LVGL库入门教程-LVGL动画
[ 复制链接 ]
发布帖子
WT_0213
论坛元老
132
主题
1987
回帖
2万
积分
论坛元老
勤劳的打工人
论坛元老, 积分 21515, 距离下一级还需 9978484 积分
论坛元老, 积分 21515, 距离下一级还需 9978484 积分
积分
21515
私信
4人留言
楼主
LVGL教程玩法
4723
4
2023-12-10 21:44:52
[i=s] 本帖最后由 WT_0213 于 2024-1-24 09:38 编辑 [/i]
动画可以说是 LVGL 中的特色之一,不过在使用动画前,请确保单片机具有足够的性能来维持足够的帧率。 ## transition:过渡动画 当一个控件的状态发生改变时,可以让样式也发生变化以提醒用户。通过过渡动画(transition)可以让样式的改变更自然。例如,按钮在点击时,以及开关在切换时,都具有一小段的过渡动画。 过渡动画使用 `lv_style_transition_dsc_t` 结构描述。为了要设置过渡动画,需要提供以下信息: * 哪些属性需要过渡 * 过渡前的延时 * 过渡持续的时间 * 过渡动画(以回调函数的形式提供) 这些信息和结构成员是一一对应的。除了直接给结构成员赋值外,也可以使用以下初始化函数一次性设置: ```cpp void lv_style_transition_dsc_init( lv_style_transition_dsc_t* tr, const lv_style_prop_t props[], lv_anim_path_cb_t path_cb, uint32_t time, uint32_t delay, void* user_data); ``` 第一个参数需要提供被初始化的过渡动画结构,第二个参数数组和字符串一样需要以 `0` 结尾。例如,假设需要实现这样一个过渡效果:点击时背景颜色发生改变并拉长,那么相应的初始化过程为: ```cpp static lv_style_transition_dsc_t trans; static const lv_style_prop_t trans_props[] = { LV_STYLE_WIDTH, LV_STYLE_HEIGHT, LV_STYLE_BG_COLOR, 0, }; lv_style_transition_dsc_init(&trans, trans_props, lv_anim_path_ease_in_out, 500, 0, NULL); ``` 这里使用的过渡函数为 `lv_anim_path_ease_in_out()` ,这是一个内置的过渡效果,与之类似的过渡lv\_anim\_path\_ease\_out函数可以参考下表: | 过渡函数 | 过渡效果 | | ---------------------------- | -------------------------------------- | | `lv_anim_path_linear` | 等速过渡 | | `lv_anim_path_ease_in` | 先慢后快的过渡 | | `lv_anim_path_ease_out` | 先快后慢的过渡 | | `lv_anim_path_ease_in_out` | 先慢、后快、结尾再变慢的过渡 | | `lv_anim_path_overshoot` | 幅度会稍微过头一些再弹回的过渡 | | `lv_anim_path_bounce` | 和上一个类似,不过会比较快地多弹几次 | | `lv_anim_path_step` | 一步到位,和没动画的区别在于多了个延时 | 过渡动画是控件样式的一部分,可以将初始化得到的过渡动画描述应用到样式上: ```cpp static lv_style_t style_trans; lv_style_init(&style_trans); lv_style_set_transition(&style_trans, &trans); ``` 过渡动画只有在两种样式切换时才会发生。例如,如果让以上样式应用在按下状态下: ```cpp lv_style_set_bg_color(&style_trans, lv_palette_main(LV_PALETTE_RED)); lv_style_set_width(&style_trans, 150); lv_style_set_height(&style_trans, 60); lv_obj_add_style(obj, &style_trans, LV_STATE_PRESSED); ``` 那么只有在从其它状态变为按下时才会发生过渡:  注意松开时样式是突然转变的。如果要给这部分也添加一个过渡效果,可以给默认状态下的控件添加一个包含过渡的样式。 ## animate:通用动画 过渡只有在状态改变时才会发生,而动画可以在任意时刻进行。除此之外,两者的区别还有:过渡只是样式的一部分,而动画和样式之间是独立的。 实际上,过渡的底层也使用的是动画。 ### 创建动画 为了创建动画,需要像样式一样声明一个动画类型并初始化: ```cpp lv_anim_t anim; lv_anim_init(&anim); ``` 由于动画是立即执行的,因此可以使用自动变量存储。然后,需要明确该动画将作用于哪一个控件: ```cpp lv_anim_set_var(&anim, obj); ``` 接下来,可以设置动画的各种轨迹,包括: * 动画需要改变什么属性 * 这些属性改变的范围 * 动画效果 * 延时和持续时间 动画的这些属性和过渡是类似的。例如,假设想做一个控件下落的动画,那么需要提供一个改变 y 坐标值的回调函数,这个函数可以直接使用 `lv_obj_set_y()` ,然后设定改变的始末值和运动轨迹,对应的代码为: ```cpp lv_anim_set_exec_cb(&anim, (lv_anim_exec_xcb_t)lv_obj_set_y); lv_anim_set_values(&anim, -100, 100); lv_anim_set_path_cb(&anim, lv_anim_path_bounce); lv_anim_set_time(&anim, 1000); lv_anim_set_delay(&anim, 1000); ``` 然后,可以在必要的时候执行动画: ```cpp lv_anim_start(&anim); ``` 效果为:  > **关于延迟渲染** > 之前说过,样式是延迟渲染的,因此样式变量需要使用 `static` 存储类型修饰符;而动画不是,动画从创建到执行是立即发生的。这也很好理解:样式在创建的过程中可能发生多次修改,因此需要确定最终的表现结果如何,再着手绘制,否则整个控件可能会重绘多次,占用大量无效的资源。 > 这种特点可能会带来许多意想不到的问题。例如,假设在 `lv_anim_set_values()` 函数中去获取一个控件的位置、宽度等信息,由于它们都属于样式的一部分,此时还没有实际计算,因此得到的可能是默认值,造成动画始末效果偏离预期轨迹。 > 要解决这个问题,要么手动设置具体的值,要么让动画等到实际渲染发生了再执行,例如将其作为事件回调函数中的一部分。 ### 更复杂的动画 以上创建的动画是单次不重复的,LVGL 提供了许多函数,可以为动画设置更复杂的属性。 这里介绍一个控件 bar ,它实质上就是没有 knob 部分的滑块,可以借用该控件来创建一个进度条(progress bar)动画。以下创建一个 bar 并将它的模式设定为 `LV_BAR_MODE_RANGE` ,这样就可以同时修改 indicator 两端的位置了: ```cpp lv_obj_t* bar = lv_bar_create(lv_scr_act()); lv_bar_set_mode(bar, LV_BAR_MODE_RANGE); ``` 这里使用官方文档中提供的一个样式来使外观更好看,具体细节就无需解释了: ```cpp static lv_style_t style_bg; static lv_style_t style_indic; lv_style_init(&style_bg); lv_style_set_border_color(&style_bg, lv_palette_main(LV_PALETTE_BLUE)); lv_style_set_border_width(&style_bg, 2); lv_style_set_pad_all(&style_bg, 6); lv_style_set_radius(&style_bg, 6); lv_style_set_anim_time(&style_bg, 1000); lv_style_init(&style_indic); lv_style_set_bg_opa(&style_indic, LV_OPA_COVER); lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE)); lv_style_set_radius(&style_indic, 3); lv_obj_remove_style_all(bar); lv_obj_add_style(bar, &style_bg, 0); lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR); lv_obj_set_size(bar, 200, 20); ``` 然后就可以确定动画效果了。例如,这里期望的动画效果为:  那么首先可以编写一个改变属性的回调函数,例如改变 indicator 的范围: ```cpp static void anim_progress_load(void* obj, int32_t v) { lv_bar_set_start_value(obj, v, LV_ANIM_ON); lv_bar_set_value(obj, 20 + v, LV_ANIM_ON); } ``` 这些值在 0\~80 范围内等速改变,持续时间 1.5 秒,无延时,对应的代码为: ```cpp lv_anim_set_exec_cb(&anim, anim_progress_load); lv_anim_set_values(&anim, 0, 80); lv_anim_set_path_cb(&anim, lv_anim_path_linear); lv_anim_set_time(&anim, 1500); lv_anim_set_delay(&anim, 0); ``` 然后这里为其添加一个倒退和重复效果,这样动画就能来回播放了: ```cpp lv_anim_set_playback_time(&anim, 1500); lv_anim_set_repeat_count(&anim, LV_ANIM_REPEAT_INFINITE); ``` 实现的进度条动画就像以上 gif 展示的一样。除此之外,还可以修改更多动画的细节,例如: | 函数 | 设置内容 | | ------------------------------------------- | ---------------------------------------------------- | | `lv_anim_set_start_cb(anim, start_cb)` | 在延时后、开始前执行一个函数 | | `lv_anim_set_playback_delay(anim, delay)` | 设置动画倒退前的延时 | | `lv_anim_set_repeat_delay(anim, delay)` | 设置动画重复前的延时 | | `lv_anim_set_early_apply(&a, bool)` | 是否将起始值应用到动画开始前,使动画执行时不会太突兀 | 更多的细节可以参考官方文档。 ### 组合动画效果 有时候需要同时播放较多动画,此时如果逐个播放的话,需要逐个为动画设计延时,不方便安排。此时,可以使用 LVGL 提供的时间线(timeline)统一安排各个动画。 时间线的创建非常简单。首先,创建一系列动画,但先不调用 `lv_anim_start()` 让动画开始。 其次,创建一个时间线并将各个动画添加到时间线的某一时刻处: ```cpp lv_anim_timeline_t* anim_timeline = lv_anim_timeline_create(); lv_anim_timeline_add(anim_timeline, 0, &anim_axis); lv_anim_timeline_add(anim_timeline, 100, &anim_obj_01); lv_anim_timeline_add(anim_timeline, 1100, &anim_obj_02); lv_anim_timeline_add(anim_timeline, 2100, &anim_obj_03); lv_anim_timeline_add(anim_timeline, 300, &anim_label_01); lv_anim_timeline_add(anim_timeline, 1300, &anim_label_02); lv_anim_timeline_add(anim_timeline, 2300, &anim_label_03); ``` 使用时间线时,无需为动画设计延时,只需要关注动画会在什么时刻播放,延时便会自动计算。 添加完毕后,再调用时间线的执行函数就可以了: ```cpp lv_anim_timeline_start(anim_timeline); ``` 这样就可以创建很复杂的组合动画效果了:  使用时间线可以方便管理所有动画,可以将时间线上包含的所有动画停播、倒放、跳转等。以下列出了一些常用的时间线控制函数: | 函数 | 用途 | | ----------------------------------------------------- | ---------------------- | | `lv_anim_timeline_stop(timeline)` | 暂停播放当前的所有动画 | | `lv_anim_timeline_set_reverse(timeline, bool)` | 设置接下来的播放方向 | | `lv_anim_timeline_set_progress(timeline, progress)` | 跳转到播放进度 | 如果需要倒放,在设置了播放方向后还需要调用 `lv_anim_timeline_start()` 重新播放,并且会从当前位置倒放。 ## scroll:滚动动画 ### 滚动的特点 滚动也是常见的一种动画效果。如果一个容器的尺寸不足以容纳它包含的控件,那么它就可以通过滚动来展示包含控件的所有部分。 为了使一个控件是可滚动的,它需要拥有标志 `LV_OBJ_FLAG_SCROLLABLE` 。清除该标志可以隐藏子控件的溢出部分。 滚动是可以冒泡的,如果一个控件已经滚动到底,再次对其尝试滚动将使滚动事件传播到父容器上。可以通过清除 `LV_OBJ_FLAG_SCROLL_CHAIN` 标志位去除这个性质。 可以通过 `lv_obj_set_scroll_dir()` 限制滚动的方向。例如: ```cpp lv_obj_set_scroll_dir(obj, LV_DIR_RIGHT); ``` 那么就只能向右滚动到底,不能向左折回。 还可以通过以下几个函数利用代码执行滚动: ```cpp lv_obj_scroll_to(obj, x, y, anim_en); lv_obj_scroll_by(obj, x, y, anim_en); lv_obj_scroll_to_view(child, anim_en); ``` 注意前两个函数的区别:前者是滚动到相应的位置,多次调用只有第一次实际有效;后者是模拟滚动的操作,实际滚动方向是相反的,并且多次调用效果可以叠加。除此之外,后者甚至可以滚动到超出子控件的范围之外。最后一个函数自动滚动到合适的位置,确保子控件可视。 这几个函数都不受滚动方向的约束。它们都具有第三个参数,用于指定滚动时是否提供滚动动画。 ### 滚动动画 滚动是有动画的,默认情况下,滚动动画的特点表现在以下几点: * 滚动是具有惯性的,意思是当输入设备停止交互时,控件还会继续向前滚动一小段距离。可以通过清除 `LV_OBJ_FLAG_SCROLL_MOMENTUM` 标志位取消这个特征 * 滚动是具有弹性的,当滚动到底时,继续尝试滚动会使控件超出一定范围,松开后回弹。可以通过清除 `LV_OBJ_FLAG_SCROLL_ELASTIC` 标志位取消这个特征 * 除此之外,以上介绍的两个代码实现滚动的函数,如果在第三个参数中应用滚动,那么会发生一小段 easy-out 的切换动画 还可以设置一种特殊的滚动效果 snap ,它使滚动时可以自动对齐。为了启用这种效果,需要添加 `LV_OBJ_FLAG_SNAPPABLE` 标志位,然后设置对齐的方式: ```cpp lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_START); ``` 这样便可以按开始位置对齐了:  还可以配合 `LV_OBJ_FLAG_SCROLL_ONE` 标志位一次只滚过最多一个控件的位置。 --- 在滚动时,会触发 `LV_EVENT_SCROLL` 事件,可以通过在该事件回调函数中对包含的子控件做变换,实现更复杂的滚动效果。 例如,以下在事件回调函数内,根据每个子控件当前位置的纵坐标对横坐标做一些变换: ```cpp static scrool_widget_cb(lv_event_t* e) { lv_obj_t* cont = lv_event_get_target(e); uint32_t child_cnt = lv_obj_get_child_cnt(cont); for (uint8_t i = 0; i < child_cnt; i++) { lv_obj_t* child = lv_obj_get_child(cont, i); lv_obj_set_style_translate_x(child, child->coords.y1 * 0.5 - 60, 0); } } ``` 然后让每次滚动时都做以上变换: ```cpp lv_obj_add_event_cb(cont, scrool_widget_cb, LV_EVENT_SCROLL, NULL); ``` 这样就能实现斜方向的滚动效果了:  这里由于仅在事件中才修改按钮的水平位置,因此一开始控件的摆放不是倾斜的。要解决这个问题,可以添加以下代码: ```cpp lv_obj_scroll_to_view(lv_obj_get_child(cont, 0), LV_ANIM_OFF); lv_event_send(cont, LV_EVENT_SCROLL, NULL); ``` 前者使各个控件的坐标被计算,后者手动触发事件回调函数,利用计算出的坐标执行位置变换。 LVGL 的官方文档还给出了一个示例,可以实现类似圆形的旋转滚动,效果非常不错,不过涉及的计算较多,感兴趣的可以自行阅读官方文档。 ### 滚动条 如果一个控件可以发生滚动,那么它就具有滚动条(scrollbar)。可以通过 `lv_obj_set_scrollbar_mode()` 函数修改滚动条的模式。例如,使用 `LV_SCROLLBAR_MODE_OFF` 模式可以使滚动条完全消失,就像上一张 gif 显示的那样。 滚动条是一个控件的 `LV_PART_SCROLLBAR` 部分,可以通过选择器给滚动条加上不同的样式。 转自:[[http://frozencandles.fun/archives/425](http://frozencandles.fun/archives/425)]([http://frozencandles.fun/archives/425](http://frozencandles.fun/archives/425)) ## 参考资料/延伸阅读 [[https://docs.lvgl.io/master/overview/animation.html](https://docs.lvgl.io/master/overview/animation.html)]([https://docs.lvgl.io/master/overview/animation.html](https://docs.lvgl.io/master/overview/animation.html)) [[https://docs.lvgl.io/master/overview/scroll.html](https://docs.lvgl.io/master/overview/scroll.html)]([https://docs.lvgl.io/master/overview/scroll.html](https://docs.lvgl.io/master/overview/scroll.html)) **免责声明:** 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系进行删除。 原文作者:[冰封残烛]([https://frozencandles.fun/](https://frozencandles.fun/)) 原文地址:[[https://frozencandles.fun/archives/425](https://frozencandles.fun/archives/425)]([https://frozencandles.fun/archives/425](https://frozencandles.fun/archives/425))
点赞
1
收藏
0
淘帖
1
────
1
人觉得很赞
────
本帖被以下淘专辑推荐:
·
LVGL
|
主题: 19, 订阅: 3
回复
使用道具
举报
4 回复
电梯直达
正序浏览
倒序浏览
正序浏览
沙发
lazy
回复
使用道具
举报
2023-12-10 22:11:34
赞
回复
评论
使用道具
举报
板凳
iiv
回复
使用道具
举报
2023-12-10 22:42:53
大佬,收下我的膝盖,高产似母猪
回复
评论
使用道具
举报
地板
干簧管
回复
使用道具
举报
2023-12-11 09:11:54
大佬牛
回复
评论
使用道具
举报
5
#
san
回复
使用道具
举报
2023-12-12 22:35:52
顶
回复
评论
使用道具
举报
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
立即登录
手机登录
点评
高级模式
本版积分规则
回帖并转播
回帖后跳转到最后一页
返回
浏览过的版块
小安派&M61环境搭建、编译烧录教程
Ai-M61-Kit外设移植教程
今日推荐
【问题】Ai-WV02-32S 短路
【B站/视频号直播预告】莫工带你跑通 AI→MCP 协议→硬件执行全
📘 一篇帖,把矽典微毫米波开发系列讲清楚
Ai-BV01-32S 参数全解析——一颗语音模组的底牌,规格书里没写的
第十期电子DIY——用 Ai-WV01-32S 打造一个会说话的AI 小玩意
【DIY小项目分享】AI语音便携可调电源
ai wb2 串口调试,疯狂输出乱码
BW16打板擦除失败是什么原因
我在Application中使能了blinky sample, 程序并没有运行
机器人量产,以后会不会搬砖越来越难
热帖排行
关于bouffalo_sdk的环境搭建
【问题】Ai-WV02-32S 短路
【B站/视频号直播预告】莫工带你跑通 AI→MCP 协议→硬件执行全
📘 一篇帖,把矽典微毫米波开发系列讲清楚
Ai-WB2-12F问题请教
Ai-BV01-32S 参数全解析——一颗语音模组的底牌,规格书里没写的
AI-BS21-32S使用AT指令都是Unknown cmd
Ra-01SC-P使用
统计信息
会员数: 31129 个
话题数: 44727 篇
首页
分类
我的