5.3. ui

5.3.1. ui 控件介绍

  • 基础控件:LVGL原生基础组件

  • 容器控件:LVGL原生容器组件

  • 菜单控件:杰理开发的专属菜单组件(以库形式提供)

  • 组合控件:由基础控件组合而成的复合组件

  • 自定义控件:杰理开发的专属组件(以库形式提供)

  • 歌词控件:歌词控件demo案例演示

5.3.2. 基础控件

  • 页面

    页面控件是lvgl中非常重要的一个控件,它可以用来创建多个页面,并且可以切换不同的页面。页面控件有三种类型,分别是 标准页面顶层页面动态页面

    lv_obj_t * page = lv_page_create(lv_scr_act());
    lv_obj_set_size(page, 200, 150);
    lv_obj_center(page);
    

    使用UI设计工具创建页面:

    页面文档
  • 按钮

    按钮控件,用于触发事件。是LVGL中最基础的控件之一。

    lv_obj_t * btn = lv_btn_create(lv_scr_act());
    lv_obj_center(btn);
    lv_obj_add_event_cb(btn, my_event_handler, LV_EVENT_CLICKED, NULL);
    

    使用UI设计工具创建按钮:

    按钮文档
  • 图片按钮

    图片按钮按钮 控件类似,但是图片按钮可以设置多个图片,根据不同状态显示不同图片。

    lv_obj_t * imgbtn = lv_imgbtn_create(lv_scr_act());
    lv_imgbtn_set_src(imgbtn, LV_IMGBTN_STATE_RELEASED, NULL, &img_normal, NULL);
    lv_imgbtn_set_src(imgbtn, LV_IMGBTN_STATE_PRESSED, NULL, &img_pressed, NULL);
    

    使用UI设计工具创建图片按钮:

    图片按钮文档
  • 标签

    标签控件用于显示文本信息。

    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello JieLi!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
    

    使用UI设计工具创建标签:

    标签文档
  • 图片

    图片控件用于显示图片资源,支持图片遮罩、缩放等功能。

    LV_IMG_DECLARE(my_img);
    lv_obj_t * img = lv_img_create(lv_scr_act());
    lv_img_set_src(img, &my_img);
    lv_obj_center(img);
    

    使用UI设计工具创建图片:

    图片文档
  • 文本框

    文本框控件,用于输入和显示文本。支持虚拟键盘输入、滚动条等功能。

    lv_obj_t * ta = lv_textarea_create(lv_scr_act());
    lv_textarea_set_placeholder_text(ta, "请输入内容...");
    lv_obj_set_size(ta, 200, 80);
    lv_obj_center(ta);
    

    使用UI设计工具创建文本框:

    文本框文档
  • 开关

    开关控件用于切换两种状态,例如开启和关闭。用户可以通过点击控件来切换其选中状态。

    lv_obj_t * sw = lv_switch_create(lv_scr_act());
    lv_obj_center(sw);
    lv_obj_add_event_cb(sw, switch_event_handler, LV_EVENT_VALUE_CHANGED, NULL);
    

    使用UI设计工具创建开关:

    开关文档
  • 数字微调器

    数字微调器控件,用于输入数值。

    lv_obj_t * spinbox = lv_spinbox_create(lv_scr_act());
    lv_spinbox_set_range(spinbox, 0, 100);
    lv_spinbox_set_digit_format(spinbox, 3, 0);
    lv_obj_center(spinbox);
    

    使用UI设计工具创建数字微调器:

    数字微调器文档
  • 复选框

    复选框控件用于在界面上显示一个复选框,用户可以勾选或者取消勾选。

    lv_obj_t * cb = lv_checkbox_create(lv_scr_act());
    lv_checkbox_set_text(cb, "我同意");
    lv_obj_center(cb);
    

    使用UI设计工具创建复选框:

    复选框文档
  • 下拉框

    下拉框控件,用于选择一组选项中的一个。

    lv_obj_t * dd = lv_dropdown_create(lv_scr_act());
    lv_dropdown_set_options(dd, "选项1\n选项2\n选项3");
    lv_obj_center(dd);
    

    使用UI设计工具创建下拉框:

    下拉框文档
  • 进度条

    进度条控件用于显示操作的进度。

    lv_obj_t * bar = lv_bar_create(lv_scr_act());
    lv_bar_set_range(bar, 0, 100);
    lv_bar_set_value(bar, 50, LV_ANIM_OFF);
    lv_obj_center(bar);
    

    使用UI设计工具创建进度条:

    进度条文档
  • Lottie动画

    用于在LVGL中播放Lottie动画的控件。

    lv_obj_t * lottie = lv_lottie_create(lv_scr_act());
    lv_lottie_set_src(lottie, "S:/anim.json");
    lv_obj_center(lottie);
    

    使用UI设计工具创建Lottie动画:

    Lottie动画文档
  • 帧动画

    帧动画是一个通过一系列图片快速切换来模拟动画效果的控件。

    lv_obj_t * animimg = lv_animimg_create(lv_scr_act());
    lv_animimg_set_src(animimg, frame_imgs, frame_count);
    lv_animimg_start(animimg);
    

    使用UI设计工具创建帧动画:

    帧动画文档
  • 图表

    图表组件用于在屏幕上显示动态数据,支持多种类型的图表(如折线图、柱状图等),并允许用户自定义轴线和刻度设置。通过配置属性,可以调整网格线的数量、每个序列的数据点数以及更新模式等参数,以适应不同的应用场景。

    lv_obj_t * chart = lv_chart_create(lv_scr_act());
    lv_obj_set_size(chart, 200, 150);
    lv_obj_center(chart);
    lv_chart_series_t * ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_set_next_value(chart, ser, 10);
    

    使用UI设计工具创建图表:

    图表文档
  • 滑动条

    滑动条控件用于在数值范围内选择一个值。滑动条控件通常用在需要用户输入数值的场景中,例如音量调节、亮度调节等。

    lv_obj_t * slider = lv_slider_create(lv_scr_act());
    lv_slider_set_range(slider, 0, 100);
    lv_obj_center(slider);
    

    使用UI设计工具创建滑动条:

    滑动条文档
  • 弧线

    弧线是一个用于显示进度的控件。

    lv_obj_t * arc = lv_arc_create(lv_scr_act());
    lv_arc_set_range(arc, 0, 100);
    lv_arc_set_value(arc, 75);
    lv_obj_center(arc);
    

    使用UI设计工具创建弧线:

    弧线文档
  • 仪表盘

    仪表盘组件用于显示一个数值的范围,通常用来表示速度、温度等。

    lv_obj_t * gauge = lv_meter_create(lv_scr_act());
    lv_obj_set_size(gauge, 200, 200);
    lv_obj_center(gauge);
    lv_meter_indicator_t * indic = lv_meter_add_needle_line(gauge, 4, lv_palette_main(LV_PALETTE_BLUE), -10);
    lv_meter_set_indicator_value(gauge, indic, 40);
    

    使用UI设计工具创建仪表盘:

    仪表盘文档

5.3.3. 菜单控件

  • 圆弧菜单

    圆弧菜单是一种常见的菜单样式,支持 平铺列表左圆弧列表右圆弧列表 三种菜单风格。

    使用UI设计工具创建圆弧菜单:

    圆弧菜单文档
  • 齿轮菜单

    齿轮菜单是一种常见的菜单样式,支持 顺时针、逆时针 两种方向展开菜单项。

    使用UI设计工具创建齿轮菜单:

    齿轮菜单文档
  • 列表菜单

    列表菜单是一个用于显示列表的菜单。通过改变不同的 菜单样式 , 可以实现不同风格的列表菜单,也支持用户自定义菜单样式。

    使用UI设计工具创建列表菜单:

    列表菜单文档
  • 曲线菜单

    曲线菜单控件,用于显示一个圆形菜单,菜单项会以曲线的方式展开。

    使用UI设计工具创建曲线菜单:

    曲线菜单文档
  • 网格菜单

    网格菜单是一个用于显示网格布局的菜单。通过改变不同的 菜单样式 , 可以实现不同风格的网格菜单,也支持用户自定义菜单样式。

    使用UI设计工具创建网格菜单:

    网格菜单文档
  • 万花筒菜单

    万花筒菜单(Spiral Menu)是一种环形菜单,它将多个选项分布在圆形或环形路径上。用户可以通过旋转设备或点击屏幕上的不同位置来选择不同的选项。这种类型的菜单通常用于需要快速访问大量选项的应用程序中,例如游戏、导航应用和工具类应用程序等。

    使用UI设计工具创建万花筒菜单:

    万花筒菜单文档

5.3.4. 容器控件

  • 通用容器

    通用容器是一个用来包裹其他控件的容器控件,它可以包含任意数量的子控件,子控件可以是任意类型的控件。

    lv_obj_t * cont = lv_obj_create(lv_scr_act());
    lv_obj_set_size(cont, 200, 150);
    lv_obj_center(cont);
    
    /* 在容器中添加一个按钮 */
    lv_obj_t * btn_in = lv_btn_create(cont);
    lv_obj_align(btn_in, LV_ALIGN_CENTER, 0, 0);
    
    lv_obj_t * label_in = lv_label_create(btn_in);
    lv_label_set_text(label_in, "按钮");
    lv_obj_center(label_in);
    

    使用UI设计工具创建通用容器:

    通用容器文档
  • Flex布局

    Flex布局是一种一维布局,在UI工具上,只能在一个方向上排列元素,可以是水平方向,也可以是垂直方向。

    lv_obj_t * flex_cont = lv_obj_create(lv_scr_act());
    lv_obj_set_size(flex_cont, 300, 200);
    lv_obj_center(flex_cont);
    
    /* 设置为水平排列 */
    lv_obj_set_flex_flow(flex_cont, LV_FLEX_FLOW_ROW);
    
    /* 往容器里添加 3 个按钮 */
    for(int i = 0; i < 3; i++) {
        lv_obj_t * btn = lv_btn_create(flex_cont);
        lv_obj_set_size(btn, 80, 50);
    
        lv_obj_t * label = lv_label_create(btn);
        char buf[16];
        lv_snprintf(buf, sizeof(buf), "按钮%d", i+1);
        lv_label_set_text(label, buf);
        lv_obj_center(label);
    }
    

    使用UI设计工具创建Flex布局:

    Flex布局文档

5.3.5. 歌词控件

演示案例:

只修改三个文件:lv_example_lyrics_3.c、lvgl_main.c、gui_timeline_timeline.c 。

lv_example_lyrics_3.c:

作用:放了歌词控件的创建、更新、释放函数

/*
* @file lv_example_lyrics_3.c
*
* 演示了如何调用 lv_lyrics 控件和蓝牙播歌实现简单的歌词播放 demo
*/
#include "../../lv_examples.h"
#if 1
#include "os/os_api.h"
#include "lvgl.h"
#define CONFIG_UI_RES_PATH CONFIG_ROOT_PATH // SD 路径
#define CONFIG_FONT_TTF_PATH "storage/sd0/C/xxx.ttf"  //字体
#define LYRICS_LETTER_NUM_MAX 256
static char lyrics_example3_text[LYRICS_LETTER_NUM_MAX] = "  ";
lv_obj_t *curr_obj_0 = NULL;
lv_obj_t **curr_obj_single = NULL;
int count_of_text = 0;
static char *test_text = "两只老虎跑的快";
//释放歌词
void lyrics_example3_clean(void){
    for (int i = 0;i<count_of_text;i++){
        lv_anim_del(curr_obj_single[i],NULL);
        lv_lyrics_destructor(curr_obj_single[i]);
        curr_obj_single[i] = NULL;
    }
}
//创建歌词
void lv_example_lyrics_3_letter( lv_obj_t *dest_scr, const char *text, uint16_t font_size, const char *font_file){
    lyrics_example3_clean();

    size_t text_len = strlen(text);
    uint32_t *letter_buf = (uint32_t *)lv_mem_alloc(sizeof(uint32_t) * text_len);    // 空间大小最大不会超过 text_len * 4

    uint16_t letter_num = 0;
    // 解析字符串中的每一个 unicode
    int ofs = 0;
    while (ofs < text_len) {
        uint32_t letter;
        uint32_t letter_next;
        printf("[chili] %s %d\n", __func__, __LINE__);
        _lv_txt_encoded_letter_next_2(text, &letter, &letter_next, &ofs);
        printf("ofs = %d; letter = 0x%08x; letter_next = 0x%08x.", ofs, letter, letter_next);

        letter_buf[letter_num] = letter;
        printf("info.letter_buf[%d] = 0x%08x.", letter_num, letter_buf[letter_num]);

        letter_num++;
        assert(letter_num < LYRICS_LETTER_NUM_MAX);   // 歌词字符数量过大,有需求再修改
    }
    count_of_text = letter_num;
    printf("letter_num = %d.", letter_num);
    printf("text_len = %d.",text_len);
    curr_obj_single = (lv_obj_t **)malloc(100*sizeof(lv_obj_t *));
    for (int i = 0;i<letter_num;i++){
        curr_obj_single[i] = lv_lyrics_create(dest_scr, font_file, font_size, letter_buf + i, 1);
        //lv_lyrics_set_pos(curr_obj_single[i], 0 + i*70, 0);//正常字间距
        lv_lyrics_set_pos(curr_obj_single[i], 0 + i*80, 150);
    }
    lv_mem_free(letter_buf);
    return;
}
//更新歌词
void lv_example_lyrics_3_text_input(void *dest_scr , char *new_text){
    size_t text_len = strlen(new_text);
    if (text_len > LYRICS_LETTER_NUM_MAX) {
        printf("error: new_text is too len. len = %d.", text_len);
        return;
    }

    printf("[%s] new lyrics is [%s]", __func__, new_text);

    memcpy(lyrics_example3_text, new_text, text_len);
    lyrics_example3_text[text_len] = '\0';

    lv_example_lyrics_3_letter(dest_scr,lyrics_example3_text, 64, CONFIG_FONT_TTF_PATH);
}
//调用示例
//在lvgl以外线程使用lvgl_rpc_post_func(),歌词创建在lv_layer_top()页面,test_text为输入歌词
//lvgl_rpc_post_func(lv_example_lyrics_3_text_input, 2, lv_layer_top() , test_text);
#endif

lv_main.c:

作用:在lvgl_v8_main_task中调用demo

变量全局声明和函数定义:

static char *test_text = "测试歌词";   //歌词
lv_obj_t *father_of_curr_obj_0 = NULL;   //父控件(可选)
void lyric_test_demo(void){
    extern void lv_example_lyrics_3_text_input(void *dest_scr , char *new_text);//外部引用
    lv_example_lyrics_3_text_input(father_of_curr_obj_0, test_text);   //歌词更新函数
}
../../_images/img3.png

lvgl_v8_main_task中的调用:

//jl_gui_init();
while (storage_device_ready() != true) os_time_dly(3);
father_of_curr_obj_0 = lv_obj_create(lv_scr_act());
lyric_test_demo();
gui_timeline_timeline_set_repeat_count(-1); // 无限循环(可选)
gui_timeline_timeline_set_period(500);      // 设置一次动画的周期(可选)
gui_timeline_timeline_start();              // ✅ 启动动画
../../_images/img4.png

gui_timeline_timeline.c:

作用:实现时间轴动画,完成歌词的平移、旋转、缩放

除了gui_timeline_timeline.c文件以外的文件在其他sdk里应该都是一样的,不一样将其复制过去即可,没有四个文件就自行创建

../../_images/img5.png
/*Generate Code, Do NOT Edit!*/
#if LV_USE_GUIBUILDER_SIMULATOR
#include <stdio.h>
#endif
#include <stdlib.h>
#include "lvgl.h"
#include "../gui_guider.h"
#include "./gui_timeline_timeline.h"
extern lv_obj_t *father_of_curr_obj_0;//父控件
extern lv_obj_t **curr_obj_single;//单个字数组
bool first_init = 1;  //是否第一次init
extern count_of_text; //text的字数
lv_timeline_timeline_t gui_timeline_timeline;
void set_center(lv_obj_t *obj,int statement){//设置控件obj在父控件中心,statement为1代表是歌词,为0表示普通控件
    lv_coord_t width;
    lv_coord_t height;
    lv_coord_t width_p;
    lv_coord_t height_p;
    lv_coord_t x;
    lv_coord_t y;
    if (statement){
        lv_lyrics_info *lyrics_info = (lv_lyrics_info *)lv_obj_get_user_data(obj);
        width = lyrics_info->curr_fontimg->header.w;
        height = lyrics_info->curr_fontimg->header.h;
        printf("width = %d , height = %d\n",width,height);
    }else{
        width = lv_obj_get_width(obj);
        height = lv_obj_get_height(obj);
    }
    lv_obj_t *parent = lv_obj_get_parent(obj);
    if (statement){
        width_p = 400;
        height_p = 400;
    }else{
        width_p = lv_obj_get_width(parent);
        height_p = lv_obj_get_height(parent);
    }
    x = width_p/2 - width/2;
    y = height_p/2 - height/2;
    printf("set_center x = %d,y = %d\n",x,y);
    if (statement){
        lv_lyrics_set_pos(obj, x, y);
    }else {
        lv_obj_set_x(obj, x);
        lv_obj_set_y(obj, y);
    }
}
//↓↓下面都是动画回调函数
void gui_timeline_set_lyrics_zoom(void *obj, int32_t v){//缩放动画
    lv_lyrics_info *lyrics_info = (lv_lyrics_info *)(((lv_obj_t *)obj)->user_data);
    lv_lyrics_set_zoom(obj, v, v);
    lv_lyrics_fontimg_redarw(obj);
}
void gui_timeline_set_lyrics_rotation(void *obj, int32_t v){//旋转动画
    lv_lyrics_info *lyrics_info = (lv_lyrics_info *)(((lv_obj_t *)obj)->user_data);
    lyrics_info->tc_point.x = 0.5f;
    lyrics_info->tc_point.y = 0.5f;
    lv_lyrics_set_rotation(obj, 0, 0, v);//在动画刷屏时才会绘制
    lv_lyrics_fontimg_redarw(obj);
}
void gui_timeline_init(struct _lv_anim_t *a){//开始动画的一些初始化
    if (first_init){
        lv_obj_set_width(father_of_curr_obj_0, 400);
        lv_obj_set_height(father_of_curr_obj_0, 400);
        set_center(father_of_curr_obj_0,0);
        lv_obj_set_style_bg_opa(father_of_curr_obj_0, LV_OPA_TRANSP, LV_PART_MAIN | LV_STATE_DEFAULT); // 背景透明
        lv_obj_set_style_border_width(father_of_curr_obj_0, 0, LV_PART_MAIN | LV_STATE_DEFAULT);      // 去边框
        lv_obj_set_style_radius(father_of_curr_obj_0, 0, LV_PART_MAIN | LV_STATE_DEFAULT);            // 去圆角
        lv_obj_set_style_shadow_width(father_of_curr_obj_0, 0, LV_PART_MAIN | LV_STATE_DEFAULT);      // 去阴影
        first_init = 0;
    }
    set_center(father_of_curr_obj_0,0);
    for (int i = 0;i<count_of_text;i++){
        lv_lyrics_set_pos(curr_obj_single[i], 0 + i*80, 150);
    }
}
void gui_timeline_set_obj_y(void * var, int32_t v){//平移控件y坐标动画
    lv_obj_set_y((lv_obj_t *)var, v);
}
void gui_timeline_set_obj_x(void * var, int32_t v){//平移控件x坐标动画
    lv_obj_set_x((lv_obj_t *)var, v);
}
void gui_timeline_set_lyrics_y(void *var,int32_t v){//平移歌词动画
    lv_lyrics_set_y((lv_obj_t *)var, v);
}
void gui_timeline_timeline_end_cb(struct _lv_anim_t *a){//结束动画
    if(gui_timeline_timeline._repeat_count == -1) {
        gui_timeline_timeline_start();
    } else if(gui_timeline_timeline._repeat_count > 0) {
        gui_timeline_timeline._repeat_count--;
        gui_timeline_timeline_start();
    }
}
void gui_timeline_set_opa(void *var,int32_t v){//透明度渐变动画
    lv_obj_set_style_bg_img_opa((lv_obj_t *)var,v,LV_PART_MAIN);
}
//↑↑上面都是动画回调函数
int32_t gui_timeline_timeline_init(lv_ui *ui){//设置动画持续时间、执行开始时间、给obj绑定动画回调函数初始化
    gui_timeline_timeline.timeline = lv_anim_timeline_create();
    lv_anim_t home_view_1_1_init;
    lv_anim_init(&home_view_1_1_init);
    lv_anim_set_var(&home_view_1_1_init, father_of_curr_obj_0);
    lv_anim_set_start_cb(&home_view_1_1_init, gui_timeline_init);
    lv_anim_set_time(&home_view_1_1_init, 10);
    lv_anim_timeline_add(gui_timeline_timeline.timeline, 0, &home_view_1_1_init);
    lv_anim_t home_view_1_top_1_0_a;
    lv_anim_init(&home_view_1_top_1_0_a);
    lv_anim_set_var(&home_view_1_top_1_0_a, father_of_curr_obj_0);
    lv_anim_set_early_apply(&home_view_1_top_1_0_a, false);
    lv_anim_set_values(&home_view_1_top_1_0_a, 140, -300);
    lv_anim_set_exec_cb(&home_view_1_top_1_0_a, gui_timeline_set_obj_y);
    lv_anim_set_path_cb(&home_view_1_top_1_0_a, lv_anim_path_linear);
    lv_anim_set_time(&home_view_1_top_1_0_a, 2000);
    lv_anim_timeline_add(gui_timeline_timeline.timeline, 10, &home_view_1_top_1_0_a);
    lv_anim_t home_view_1_left_1_0_a;
    lv_anim_init(&home_view_1_left_1_0_a);
    lv_anim_set_var(&home_view_1_left_1_0_a, father_of_curr_obj_0);
    lv_anim_set_early_apply(&home_view_1_left_1_0_a, false);
    lv_anim_set_values(&home_view_1_left_1_0_a, 200, 500);
    lv_anim_set_exec_cb(&home_view_1_left_1_0_a, gui_timeline_set_obj_x);
    lv_anim_set_path_cb(&home_view_1_left_1_0_a, lv_anim_path_linear);
    lv_anim_set_time(&home_view_1_left_1_0_a, 2000);
    lv_anim_timeline_add(gui_timeline_timeline.timeline, 10, &home_view_1_left_1_0_a);
    for (int i = 0;i<count_of_text;i++){//给每个歌词都绑定下面的动画
        lv_anim_t lyrics_example3_play_anim_single;
        lv_anim_init(&lyrics_example3_play_anim_single);  // 初时化动画变量
        lv_anim_set_var(&lyrics_example3_play_anim_single, curr_obj_single[i]); //设置动画关联的对象img
        lv_anim_set_early_apply(&lyrics_example3_play_anim_single, false);
        lv_anim_set_exec_cb(&lyrics_example3_play_anim_single, gui_timeline_set_lyrics_rotation); //设置动画执行的回调函数set_angle
        lv_anim_set_values(&lyrics_example3_play_anim_single, 0, (i%2 == 0)?600:(-600));
        lv_anim_set_time(&lyrics_example3_play_anim_single, 1000);
        lv_anim_set_path_cb(&lyrics_example3_play_anim_single, lv_anim_path_linear);
        lv_anim_set_playback_time(&lyrics_example3_play_anim_single, 1000);
        lv_anim_timeline_add(gui_timeline_timeline.timeline, 10, &lyrics_example3_play_anim_single);
        lv_anim_t home_view_1_top_1_0_letter;
        lv_anim_init(&home_view_1_top_1_0_letter);
        lv_anim_set_var(&home_view_1_top_1_0_letter, curr_obj_single[i]);
        lv_anim_set_early_apply(&home_view_1_top_1_0_letter, false);
        lv_anim_set_values(&home_view_1_top_1_0_letter, 150, (i%2==0)?100:50);
        lv_anim_set_exec_cb(&home_view_1_top_1_0_letter, gui_timeline_set_lyrics_y);
        lv_anim_set_path_cb(&home_view_1_top_1_0_letter, lv_anim_path_linear);
        lv_anim_set_time(&home_view_1_top_1_0_letter, 2000);
        lv_anim_timeline_add(gui_timeline_timeline.timeline, 10, &home_view_1_top_1_0_letter);
        lv_anim_t home_view_1_top_1_0_letter_opa;
        lv_anim_init(&home_view_1_top_1_0_letter_opa);
        lv_anim_set_var(&home_view_1_top_1_0_letter_opa, curr_obj_single[i]);
        lv_anim_set_early_apply(&home_view_1_top_1_0_letter_opa, false);
        lv_anim_set_values(&home_view_1_top_1_0_letter_opa, 255, 0);
        lv_anim_set_exec_cb(&home_view_1_top_1_0_letter_opa, gui_timeline_set_opa);
        lv_anim_set_path_cb(&home_view_1_top_1_0_letter_opa, lv_anim_path_linear);
        lv_anim_set_time(&home_view_1_top_1_0_letter_opa, 1000);
        lv_anim_timeline_add(gui_timeline_timeline.timeline, 10, &home_view_1_top_1_0_letter_opa);
    }
    lv_anim_t timeline_end_a;
    lv_anim_init(&timeline_end_a);
    lv_anim_set_time(&timeline_end_a, gui_timeline_timeline._period);
    lv_anim_set_deleted_cb(&timeline_end_a, gui_timeline_timeline_end_cb);
    lv_anim_timeline_add(gui_timeline_timeline.timeline, 1100, &timeline_end_a);
    return 0;
}
//↓↓下面都是默认存在的函数(无需修改)
void gui_timeline_timeline_start(){
    if (gui_timeline_timeline.timeline) {
        int32_t temp_repeat_count = gui_timeline_timeline._repeat_count;
        gui_timeline_timeline._repeat_count = 0;
        lv_anim_timeline_del(gui_timeline_timeline.timeline);
        gui_timeline_timeline._repeat_count = temp_repeat_count;
    }
    int32_t res = gui_timeline_timeline_init(&guider_ui);
    if(res != -1) {
        lv_anim_timeline_start(gui_timeline_timeline.timeline);
    }
}
void gui_timeline_timeline_stop(){
    gui_timeline_timeline._repeat_count = 0;
    if(gui_timeline_timeline.timeline) {
        lv_anim_timeline_stop(gui_timeline_timeline.timeline);
    }
}
void gui_timeline_timeline_delete(){
    gui_timeline_timeline._repeat_count = 0;
    gui_timeline_timeline._period = 0;
    if(gui_timeline_timeline.timeline) {
        lv_anim_timeline_del(gui_timeline_timeline.timeline);
        gui_timeline_timeline.timeline = NULL;
    }
}
void gui_timeline_timeline_set_period(uint32_t period){
    gui_timeline_timeline._period = period;
}
void gui_timeline_timeline_set_repeat_count(int32_t count){
    gui_timeline_timeline._repeat_count = count;
}

demo中的所有歌词一起平移是用了一个父控件实现的father_of_curr_obj_0

其他动画的回调函数逻辑都比较易懂,看代码即可,下面举个例子 :

../../_images/img6.png

最终效果:

../../_images/video1.gif

下一页详细查看杰理UI工具的用法